Skip to content
Advertisement

What’s the purpose of the 3rd argument in useReducer?

From the docs:

[init, the 3d argument] lets you extract the logic for calculating the initial state outside the reducer. This is also handy for resetting the state later in response to an action.

And the code:

function init(initialCount) {
  return { count: initialCount };
}

function reducer(state, action) {
  switch (action.type) {
    ...
    case 'reset':
      return init(action.payload);
    ...
  }
}

function Counter({initialCount}) {
  const [state, dispatch] = useReducer(reducer, initialCount, init);
  ...
}

Why would I do that over reusing a constant initialState?

const initialState = {
  count: 5,
};

function reducer(state, action) {
  switch (action.type) {
    ...
    case 'reset':
      return initialState;
    ...
  }
}

function Counter({initialCount}) {
  const [state, dispatch] = useReducer(reducer, initialState);
  ...
}

Looks less verbose to me.

Advertisement

Answer

EDIT july 2020: React documentation has now better explainations on this arg called lazy initializer. Using this function in another way could result to breaking changes due to undocumented effect. Following answer remain valid.


As far as I can experiment, the init function as third arg is a transformer of the initialState.

It means that initialState will not be used a initial state, but as arg for init function. The return of this one will be the true initialState. It could be usefull to avoid huge param during the useReducer initialization line.

/* Here is the magic. The `initialState` pass to 
 * `useReducer` as second argument will be hook
 * here to init the real `initialState` as return
 * of this function
 */
const countInitializer = initialState => {
  return {
    count: initialState,
    otherProp: 0
  };
};

const countReducer = state => state; // Dummy reducer

const App = () => {
  const [countState /*, countDispatch */] =
    React.useReducer(countReducer, 2, countInitializer);

  // Note the `countState` will be initialized state direct on first render
  return JSON.stringify(countState, null, 2);
}

ReactDOM.render(<App />, document.body);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.4/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.4/umd/react-dom.production.min.js"></script>
Advertisement