DEV Community

Anthony Frehner
Anthony Frehner

Posted on

useReducer ReactJS gotcha

Question: Is there a difference between these two useReducers in the following codesandbox?

https://codesandbox.io/s/frosty-dubinsky-no5rf?file=/src/App.js

import React, { useReducer } from "react";

export default function App() {
  const [state1, dispatch1] = useReducer(reducer1, 0);
  const [state2, dispatch2] = useReducer(reducer2, 0);

  return (
    <div className="App">
      <div>1: {`${state1}`}</div>
      <div>2: {`${state2}`}</div>
      <button
        onClick={() => {
          dispatch1(1);
          dispatch2(state2 + 1);
        }}
      >
        Click
      </button>
    </div>
  );
}

function reducer1(state, action) {
  return state + action;
}

function reducer2(state, action) {
  return action;
}
Enter fullscreen mode Exit fullscreen mode

Answer: yes. By using the state that is automatically passed in, reducer1 is safe to be called multiple times because it always gets the most up-to-date state.

reducer2 is not safe to call multiple times because it looks at stale state when itโ€™s called subsequent times. Here's an example of where it breaks:

https://codesandbox.io/s/bitter-currying-bsx6g?file=/src/App.js

//answer: run this code
import React, { useReducer } from "react";

export default function App() {
  const [state1, dispatch1] = useReducer(reducer1, 0);
  const [state2, dispatch2] = useReducer(reducer2, 0);

  return (
    <div className="App">
      <div>1: {`${state1}`}</div>
      <div>2: {`${state2}`}</div>
      <button
        onClick={() => {
          dispatch1(1);
          dispatch1(1);
          dispatch2(state2 + 1);
          dispatch2(state2 + 1);
        }}
      >
        Click
      </button>
    </div>
  );
}

function reducer1(state, action) {
  return state + action;
}

function reducer2(state, action) {
  return action;
}
Enter fullscreen mode Exit fullscreen mode

Discussion (0)