type A = any;
type B = any;
type STATE = {
a: A;
b: B;
}
type ACTION =
| {type: 'changeA', payload: any}
| {type: 'changeB', payload: any}
type REDUCER = <T extends {}>(state: T, action: ACTION) => STATE
type SLICES = {
a: REDUCER<A>;
b: REDUCER<B>;
}
// reduce 写法
const combineReducers = (slices: SLICES) => (state:STATE, action:ACTION):STATE =>
// use for..in loop, if you prefer it
Object.keys(slices).reduce(
(state, key) => ({
...acc,
[key]: slices[key](state[key], action),
}),
state
);
// for...in 写法
const combineReducers = (slices: SLICES) => (state:STATE, action:ACTION):STATE => {
let newState = {}
for (let [key, reducer] of Object.entries(slices)) {
newState = {
...state,
[key]: reducer(state[key], action)
}
}
return newState
}
Example:
import a from "./Reducer1";
import b from "./Reducer2";
const initialState = { a: {}, b: {} }; // some state for props a, b
const 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>
);
};
const [s1, d1] = useReducer(a, {}); // some init state {}
const [s2, d2] = useReducer(b, {}); // some init state {}
// don't forget to memoize again
const 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
useReducer - combine reducers
参考链接: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:
Example:
Combine reducers in sequence
Apply multiple reducers in sequence on state with arbitrary shape, akin to reduce-reducers:
Example:
Combine multiple
useReducer
HooksYou could also combine dispatch and/or state from multiple
useReducer
s, like:Example:
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 bothcombineReducers
andreduceReducers