UseReducer is an alternative to useState. When useState does not meet our needs well, useReducer may solve our problems.
usage
const [state, dispatch] = useReducer(reducer, initialArg, init);
The first reducer is the function (state, action) => newState, which accepts the current state and action. The second parameter initialArg is the initial state value. The third argument init is the lazy initialization function.
Use an official example to see how it works
const initialState = {count: 0};
function reducer(state, action) {
switch (action.type) {
case 'increment':
return {count: state.count + 1};
case 'decrement':
return {count: state.count - 1};
default:
throw new Error();
}
}
function Counter() {
const [state, dispatch] = useReducer(reducer, initialState);
return (
<>
Count: {state.count}
<button onClick={()= > dispatch({type: 'decrement'})}>-</button>
<button onClick={()= > dispatch({type: 'increment'})}>+</button>
</>
);
}
Copy the code
The parameters of dispatch are the Reducer actions. The Reducer function performs some logic based on the incoming actions and returns the new state.
use
-
Dispatches can be passed to child components in place of callbacks for updates from the bottom up. The advantage is that dispatch is not redefined during updates, which reduces the overhead of redefining callback functions and makes it easier for sub-components to determine whether updates are needed based on props.
If the hierarchy is too deep, it can also be used with context, where using Dispatch instead of callback is more advantageous. Because dispatch is invariant in re-render, it does not cause components using the context to perform meaningless updates.
-
React does not process updates outside events in batches. Reducer can be used to avoid this problem.
const reducer = (state, action) = > { switch(action.type) { case 'update': return { ...state, data: action.payload.data, loading: false,}default: returnstate; }}// The event is triggered dispatch({ type: 'update'.payload: { data }}) // Or simply const reducer = (state, newState) = > { return{... state, ... newState} }const [state, dispatch] = useReducer(reducer, {loading: true.data: null.something: ' '}) / / triggers dispatch({loading: false}) Copy the code
The essence is to put state in the same place, but more readable than useState.
-
ForceUpdate useState and useReducer skip updates if they have the same value. There is no mandatory update method for function components. We can use useReducer to simulate one.
const [, forceUpdate] = useReducer(x= > x + 1.0) function onClick = () = >{ forceUpdate() } Copy the code
conclusion
UseReducer is an alternative to useState. It does everything useState can do and does it better. UseReducer decouples the logic of actions from subsequent actions (typically UI updates) to a certain extent, resulting in more code but a cleaner look.