Skip to content

Commit d933f65

Browse files
committed
docs
1 parent 32d1fbd commit d933f65

File tree

3 files changed

+187
-9
lines changed

3 files changed

+187
-9
lines changed

docs/api/createDynamicMiddleware.mdx

Lines changed: 181 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,181 @@
1+
---
2+
id: createDynamicMiddleware
3+
title: createDynamicMiddleware
4+
sidebar_label: createDynamicMiddleware
5+
hide_title: true
6+
---
7+
8+
 
9+
10+
# `createDynamicMiddleware`
11+
12+
## Overview
13+
14+
A "meta-middleware" that allows adding middleware to the dispatch chain after store initialisation.
15+
16+
## Instance Creation
17+
18+
```ts no-transpile
19+
import { createDynamicMiddleware, configureStore } from '@reduxjs/toolkit'
20+
21+
const dynamicMiddleware = createDynamicMiddleware()
22+
23+
const store = configureStore({
24+
reducer: {
25+
todos: todosReducer,
26+
},
27+
middleware: (getDefaultMiddleware) =>
28+
getDefaultMiddleware().prepend(dynamicMiddleware.middleware),
29+
})
30+
```
31+
32+
:::tip
33+
34+
It's possible to pass two type parameters to `createDynamicMiddleware`, `State` and `Dispatch`.
35+
36+
These are used by methods that receive middleware to ensure that the provided middleware are compatible with the types provided.
37+
38+
```ts no-transpile
39+
const dynamicMiddleware = createDynamicMiddleware<State, Dispatch>()
40+
```
41+
42+
However, if these values are derived from the store (as they should be), a circular type dependency is formed.
43+
44+
As a result, it's better to use the `withTypes` helper attached to `addMiddleware`, `withMiddleware` and `createDispatchWithMiddlewareHook`.
45+
46+
```ts no-transpile
47+
import { createDynamicMiddleware } from '@reduxjs/toolkit/react'
48+
import type { RootState, AppDispatch } from './store'
49+
50+
const dynamicMiddleware = createDynamicMiddleware()
51+
52+
const {
53+
middleware,
54+
addMiddleware,
55+
withMiddleware,
56+
createDispatchWithMiddlewareHook,
57+
} = dynamicMiddleware
58+
59+
interface MiddlewareApiConfig {
60+
state: RootState
61+
dispatch: AppDispatch
62+
}
63+
64+
export const addAppMiddleware = addMiddleware.withTypes<MiddlewareApiConfig>()
65+
66+
export const withAppMiddleware = withMiddleware.withTypes<MiddlewareApiConfig>()
67+
68+
export const createAppDispatchWithMiddlewareHook =
69+
createDispatchWithMiddlewareHook.withTypes<MiddlewareApiConfig>()
70+
71+
export default middleware
72+
```
73+
74+
:::
75+
76+
## Dynamic Middleware Instance
77+
78+
The "dynamic middleware instance" returned from `createDynamicMiddleware` is an object similar to the object generated by `createListenerMiddleware`. The instance object is _not_ the actual Redux middleware itself. Rather, it contains the middleware and some instance methods used to add middleware to the chain.
79+
80+
```ts no-transpile
81+
export type DynamicMiddlewareInstance<
82+
State = unknown,
83+
Dispatch extends ReduxDispatch<AnyAction> = ReduxDispatch<AnyAction>
84+
> = {
85+
middleware: DynamicMiddleware<State, Dispatch>
86+
addMiddleware: AddMiddleware<State, Dispatch>
87+
withMiddleware: WithMiddleware<State, Dispatch>
88+
}
89+
```
90+
91+
### `middleware`
92+
93+
The wrapper middleware instance, to add to the Redux store.
94+
95+
You can place this anywhere in the middleware chain, but note that all the middleware you inject into this instance will be contained within this position.
96+
97+
### `addMiddleware`
98+
99+
Injects a set of middleware into the instance.
100+
101+
```ts no-transpile
102+
addMiddleware(logger, listenerMiddleware.instance)
103+
```
104+
105+
:::note
106+
107+
- Middleware are compared by function reference, and each is only added to the chain once.
108+
109+
- Middleware are stored in an ES6 map, and are thus called in insertion order during dispatch.
110+
111+
:::
112+
113+
### `withMiddleware`
114+
115+
Accepts a set of middleware, and creates an action. When dispatched, it injects the middleware and returns a version of `dispatch` typed to be aware of any extensions added.
116+
117+
```ts no-transpile
118+
const listenerDispatch = store.dispatch(
119+
withMiddleware(listenerMiddleware.middleware)
120+
)
121+
122+
const unsubscribe = listenerDispatch(addListener({ type, effect }))
123+
```
124+
125+
## React Integration
126+
127+
When imported from the React-specific entry point (`@reduxjs/toolkit/react`), the result of calling `createDynamicMiddleware` will have extra methods attached.
128+
129+
_These depend on having `react-redux` installed._
130+
131+
```ts no-transpile
132+
interface ReactDynamicMiddlewareInstance<
133+
State = any,
134+
Dispatch extends ReduxDispatch<AnyAction> = ReduxDispatch<AnyAction>
135+
> extends DynamicMiddlewareInstance<State, Dispatch> {
136+
createDispatchWithMiddlewareHook: CreateDispatchWithMiddlewareHook<
137+
State,
138+
Dispatch
139+
>
140+
createDispatchWithMiddlewareHookFactory: (
141+
context?: Context<
142+
ReactReduxContextValue<State, ActionFromDispatch<Dispatch>>
143+
>
144+
) => CreateDispatchWithMiddlewareHook<State, Dispatch>
145+
}
146+
```
147+
148+
### `createDispatchWithMiddlewareHook`
149+
150+
Accepts a set of middleware, and returns a [`useDispatch`](https://react-redux.js.org/api/hooks#usedispatch) hook returning a `dispatch` typed to include extensions from provided middleware.
151+
152+
```ts no-transpile
153+
const useListenerDispatch = createDispatchWithMiddlewareHook(
154+
listenerMiddleware.instance
155+
)
156+
157+
const Component = () => {
158+
const listenerDispatch = useListenerDispatch()
159+
useEffect(() => {
160+
const unsubscribe = listenerDispatch(addListener({ type, effect }))
161+
return () => unsubscribe()
162+
}, [dispatch])
163+
}
164+
```
165+
166+
:::caution
167+
168+
Middleware is injected when `createDispatchWithMiddlewareHook` is called, not when the `useDispatch` hook is used.
169+
170+
:::
171+
172+
### `createDispatchWithMiddlewareHookFactory`
173+
174+
Accepts a React context instance, and returns a `createDispatchWithMiddlewareHook` built to use that context.
175+
176+
```ts no-transpile
177+
const createDispatchWithMiddlewareHook =
178+
createDispatchWithMiddlewareHookFactory(context)
179+
```
180+
181+
Useful if you're using a [custom context](https://react-redux.js.org/using-react-redux/accessing-store#providing-custom-context) for React Redux.

packages/toolkit/src/dynamicMiddleware/index.ts

Lines changed: 5 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -21,15 +21,11 @@ const createMiddlewareEntry = <
2121
Dispatch extends ReduxDispatch<AnyAction> = ReduxDispatch<AnyAction>
2222
>(
2323
middleware: Middleware<any, State, Dispatch>
24-
) => {
25-
const id = nanoid()
26-
const entry: MiddlewareEntry<State, Dispatch> = {
27-
id,
28-
middleware,
29-
applied: new Map(),
30-
}
31-
return entry
32-
}
24+
): MiddlewareEntry<State, Dispatch> => ({
25+
id: nanoid(),
26+
middleware,
27+
applied: new Map(),
28+
})
3329

3430
export const createDynamicMiddleware = <
3531
State = any,

website/sidebars.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@
4242
"api/immutabilityMiddleware",
4343
"api/serializabilityMiddleware",
4444
"api/createListenerMiddleware",
45+
"api/createDynamicMiddleware",
4546
"api/autoBatchEnhancer"
4647
]
4748
},

0 commit comments

Comments
 (0)