skip to Main Content

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


  1. 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

    Login or Signup to reply.
  2. Components with many state updates spread across many event handlers can get overwhelming. For these cases, you can consolidate all the state update logic outside your component in a single function, called a reducer.

    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.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search