createDynamicMiddleware
Overview
A "meta-middleware" that allows adding middleware to the dispatch chain after store initialisation.
Instance Creation
import { createDynamicMiddleware, configureStore } from '@reduxjs/toolkit'
const dynamicMiddleware = createDynamicMiddleware()
const store = configureStore({
reducer: {
todos: todosReducer,
},
middleware: (getDefaultMiddleware) =>
getDefaultMiddleware().prepend(dynamicMiddleware.middleware),
})
It's possible to pass two type parameters to createDynamicMiddleware
, State
and Dispatch
.
These are used by methods that receive middleware to ensure that the provided middleware are compatible with the types provided.
const dynamicMiddleware = createDynamicMiddleware<State, Dispatch>()
However, if these values are derived from the store (as they should be), a circular type dependency is formed.
As a result, it's better to use the withTypes
helper attached to addMiddleware
, withMiddleware
and createDispatchWithMiddlewareHook
.
import { createDynamicMiddleware } from '@reduxjs/toolkit/react'
import type { RootState, AppDispatch } from './store'
const dynamicMiddleware = createDynamicMiddleware()
const {
middleware,
addMiddleware,
withMiddleware,
createDispatchWithMiddlewareHook,
} = dynamicMiddleware
interface MiddlewareApiConfig {
state: RootState
dispatch: AppDispatch
}
export const addAppMiddleware = addMiddleware.withTypes<MiddlewareApiConfig>()
export const withAppMiddleware = withMiddleware.withTypes<MiddlewareApiConfig>()
export const createAppDispatchWithMiddlewareHook =
createDispatchWithMiddlewareHook.withTypes<MiddlewareApiConfig>()
export default middleware
Dynamic Middleware Instance
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.
export type DynamicMiddlewareInstance<
State = unknown,
Dispatch extends ReduxDispatch<UnknownAction> = ReduxDispatch<UnknownAction>,
> = {
middleware: DynamicMiddleware<State, Dispatch>
addMiddleware: AddMiddleware<State, Dispatch>
withMiddleware: WithMiddleware<State, Dispatch>
}
middleware
The wrapper middleware instance, to add to the Redux store.
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.
addMiddleware
Injects a set of middleware into the instance.
addMiddleware(logger, listenerMiddleware.instance)
-
Middleware are compared by function reference, and each is only added to the chain once.
-
Middleware are stored in an ES6 map, and are thus called in insertion order during dispatch.
withMiddleware
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.
const listenerDispatch = store.dispatch(
withMiddleware(listenerMiddleware.middleware),
)
const unsubscribe = listenerDispatch(addListener({ type, effect }))
React Integration
When imported from the React-specific entry point (@reduxjs/toolkit/react
), the result of calling createDynamicMiddleware
will have extra methods attached.
These depend on having react-redux
installed.
interface ReactDynamicMiddlewareInstance<
State = any,
Dispatch extends ReduxDispatch<UnknownAction> = ReduxDispatch<UnknownAction>,
> extends DynamicMiddlewareInstance<State, Dispatch> {
createDispatchWithMiddlewareHook: CreateDispatchWithMiddlewareHook<
State,
Dispatch
>
createDispatchWithMiddlewareHookFactory: (
context?: Context<
ReactReduxContextValue<State, ActionFromDispatch<Dispatch>>
>,
) => CreateDispatchWithMiddlewareHook<State, Dispatch>
}
createDispatchWithMiddlewareHook
Accepts a set of middleware, and returns a useDispatch
hook returning a dispatch
typed to include extensions from provided middleware.
const useListenerDispatch = createDispatchWithMiddlewareHook(
listenerInstance.middleware,
)
const Component = () => {
const listenerDispatch = useListenerDispatch()
useEffect(() => {
const unsubscribe = listenerDispatch(addListener({ type, effect }))
return () => unsubscribe()
}, [dispatch])
}
Middleware is injected when createDispatchWithMiddlewareHook
is called, not when the useDispatch
hook is used.
createDispatchWithMiddlewareHookFactory
Accepts a React context instance, and returns a createDispatchWithMiddlewareHook
built to use that context.
const createDispatchWithMiddlewareHook =
createDispatchWithMiddlewareHookFactory(context)
Useful if you're using a custom context for React Redux.