Search code examples
reactjsreduxreducers

I have built a global state redux like pattern with context and hooks. Is there a way to combine reducers?


I've built a global state provider context, and a reducer with the useReducer Hook. I'm realizing that combining multiple reducers like I would in redux is problematic. Is there a good way to do this? I have seen people importing combineReducers from redux itself, and that seems like it kind of defeats the point. Does anyone have any insight on this?


Solution

  • Not sure this is what you're looking for, but I have used something like below to combine multiple reducers. It actually reduces the reducers. Not actually like redux combineReducers with key/value.

    const reduceReducers = (...reducers) => (prevState, value, ...args) =>
      reducers.reduce(
        (newState, reducer) => reducer(newState, value, ...args),
        prevState
      );
    

    I would be used like:

    function reducerA(state, action) {
      switch (action.type) {
        case "increment":
          return { ...state, count: state.count + 1 };
        case "decrement":
          return { ...state, count: state.count - 1 };
        default:
          return state;
      }
    }
    
    function reducerB(state, action) {
      switch (action.type) {
        case "double":
          return { ...state, count: state.count * 2 };
        case "halve":
          return { ...state, count: state.count / 2 };
        default:
          return state;
      }
    }
    
    export default reduceReducers(reducerA, reducerB);
    

    Then the Component:

    import reducers from "./reducers";
    
    function Counter({ initialState = { count: 1 } }) {
      const [state, dispatch] = useReducer(reducers, initialState);
      return (
        <>
          Count: {state.count}
          <button onClick={() => dispatch({ type: "increment" })}>+</button>
          <button onClick={() => dispatch({ type: "decrement" })}>-</button>
          <button onClick={() => dispatch({ type: "double" })}>x2</button>
          <button onClick={() => dispatch({ type: "halve" })}>/2</button>
        </>
      );
    }