blog_robinwieruch_content
blog_robinwieruch_content copied to clipboard
No next method or return value in the useReducer + middleware example
In the this example, currently, the middleware does not take in account two important aspects of middlewares:
- the
nextmethod - the
return valuemechanism
The next method enables you to break the middleware chain in certain circumstances.
The return value mechanism allows you to bubble up promises or return values to the entity which invoked the dispatch method.
Perhaps something like that:
import { Reducer, useMemo, useReducer } from 'react';
type Json = Record<string, any>;
type Action = { type: string } & Json;
type Middleware = (store: any) => (next: any) => (action: Action) => any;
export function useReducerWithMiddleware<T>(
reducer: Reducer<any, any>,
initialState: T,
middlewares: Middleware[]
) {
const [state, dispatch] = useReducer(reducer, initialState);
const mockStore = useMemo(
() => ({
dispatch, //
getState: () => state,
updateReducer: () => {},
}),
[state, dispatch]
);
const dispatchWithMiddleware = (action: Action) => {
let output;
for (let middleware of middlewares) {
let nextWasCalled = false;
const next = () => {
nextWasCalled = true;
};
output = middleware(mockStore)(next)(action) || output;
if (!nextWasCalled) {
break;
}
}
dispatch(action);
};
return [state as T, dispatchWithMiddleware];
}
Which will make it possible to use the same middlewares redux signature:
const logger = (store: any) => (next: any) => (action: any) => {
console.log('dispatching', action);
let result = next(action);
console.log('next state', store.getState());
return result;
};
export const Component = (props) => {
const [state, dispatch] = useReducerWithMiddleware(
reducer,
initialState,
[logger]
);
// ...component definition...
}