React useReducer: How to combine multiple reducers? React useReducer: How to combine multiple reducers? reactjs reactjs

React useReducer: How to combine multiple reducers?


Combine slice reducers (combineReducers)

The most common approach is to let each reducer manage its own property ("slice") of the state:

const combineReducers = (slices) => (state, action) =>  Object.keys(slices).reduce( // use for..in loop, if you prefer it    (acc, prop) => ({      ...acc,      [prop]: slices[prop](acc[prop], action),    }),    state  );
Example:
import a from "./Reducer1";import b from "./Reducer2";const initialState = { a: {}, b: {} }; // some state for props a, bconst rootReducer = combineReducers({ a, b });const StoreProvider = ({ children }) => {  const [state, dispatch] = useReducer(rootReducer, initialState);  // Important(!): memoize array value. Else all context consumers update on *every* render  const store = React.useMemo(() => [state, dispatch], [state]);  return (    <StoreContext.Provider value={store}> {children} </StoreContext.Provider>  );};

Combine reducers in sequence

Apply multiple reducers in sequence on state with arbitrary shape, akin to reduce-reducers:

const reduceReducers = (...reducers) => (state, action) =>  reducers.reduce((acc, nextReducer) => nextReducer(acc, action), state);
Example:
const rootReducer2 = reduceReducers(a, b);// rest like in first variant

Combine multiple useReducer Hooks

You could also combine dispatch and/or state from multiple useReducers, like:

const combineDispatch = (...dispatches) => (action) =>  dispatches.forEach((dispatch) => dispatch(action));
Example:
const [s1, d1] = useReducer(a, {}); // some init state {} const [s2, d2] = useReducer(b, {}); // some init state {} // don't forget to memoize againconst combinedDispatch = React.useCallback(combineDispatch(d1, d2), [d1, d2]);const combinedState = React.useMemo(() => ({ s1, s2, }), [s1, s2]);// This example uses separate dispatch and state contexts for better render performance<DispatchContext.Provider value={combinedDispatch}>  <StateContext.Provider value={combinedState}> {children} </StateContext.Provider></DispatchContext.Provider>;

In summary

Above are the most common variants. There are also libraries like use-combined-reducers for these cases. Last, take a look at following sample combining both combineReducers and reduceReducers: