I’m reading the docs for useReducer
and noticed that all the examples declare the reducer function outside the body of the component, like this
import { useReducer } from 'react';
function reducer(state, action) {
if (action.type === 'incremented_age') {
return {
age: state.age + 1
};
}
throw Error('Unknown action.');
}
export default function Counter() {
const [state, dispatch] = useReducer(reducer, { age: 42 });
return (
<>
<button onClick={() => {
dispatch({ type: 'incremented_age' })
}}>
Increment age
</button>
<p>Hello! You are {state.age}.</p>
</>
);
}
Is there any substantive benefit to this or is it just a convention? In particular, I’m thinking about the stability of the function reference.
2
Answers
It does improve performance slightly to define it just once.
First, by defining it outside, you no longer have to create the function on ever render. This very slightly speeds things up. But it is admittedly quite a tiny amount of speedup (nanoseconds).
Second and more important, useReducer has some internal optimizations which can allow it to do less work if the reducer does not change. When you dispatch an action to the reducer, react immediately computes the new state. It needs to do this so it can skip the render if the state hasn’t changed. But it also saves the computed state. Later, when a render happens, if the reducer has not changed then it can used the saved state instead of computing it again.
So, if your reducer changes, then it must be run at least twice (more if concurrent rendering causes the render to abort). If it does not change, then it runs exactly once. The impact of this optimization will depend on how complex your reducer is.
See this code for where they implement this optimization: https://github.com/facebook/react/blob/main/packages/react-reconciler/src/ReactFiberHooks.js#L3223
If multiple components do some operation with the same state, declaring the reducer outside allows you to reuse it in all.
Keeping the reducer separate from the components will make your codebase easy to maintain.