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?
I have built a global state redux like pattern with context and hooks. Is there a way to combine reducers?
Sounds like you should consider start using redux instead of the hooks and enjoy some nice tooling ;) Although the redux hook has less overhead for simple usages, I don't see the benefit for multiple combined reducers. That being said, a plain combineReducers is fairly simple to implement. –
Bortz
you're right. However, I started this particular project to learn hooks INSTEAD of redux. Redux makes this a lot simpler, but I dont want to rely on it. –
Pokorny
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>
</>
);
}
gonna give this a shot. this looks like exactly what i was looking for. I'll let you know how it works out! i attempted something similar but was unsuccessful. I am a junior, and I am very familiar with map/filter but still sometimes struggle with the reduce api. –
Pokorny
this is the correct answer. I was able to do it after spending some time with curried functions. I am discovering through doing all of this though that Redux really is a lot simpler to get the same result. This method has issues like handling initialState. short of using object spread and merging seperate initialStates, or maintaining a giant object in the file I have the context declaration/provider in, there isn't a good way. –
Pokorny
@DaveFunk For handling initialState We can combine multiple states as below
const initialState = { reducerAState, reducerBState }
and then pass to useReducer –
Aspic © 2022 - 2025 — McMap. All rights reserved.