Skip to content Skip to sidebar Skip to footer

Mutating State From React's Usestate Hook

Is it, and why is it a bad idea to mutate a state from React's new useState hook? I found no info on the topic. Consider following code: const [values, setValues] = useState({}) /

Solution 1:

You should never mutate state directly as it might not even cause a re-render if you update the state with the same object reference.

const { useState } = React;

functionApp() {
  const [values, setValues] = useState({});

  constdoSomething = (name, value) => {
    values[name] = value;
    setValues(values);
  };

  return (
    <divonClick={() => doSomething(Math.random(), Math.random())}>
      {JSON.stringify(values)}
    </div>
  );
}

ReactDOM.render(<App />, document.getElementById("root"));
<scriptsrc="https://unpkg.com/react@16/umd/react.development.js"></script><scriptsrc="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script><divid="root"></div>

You can give a function as first argument to setValues just like you are used to in the class component setState, and that function in turn will get the correct state as argument, and what is returned will be the new state.

constdoSomething = (name, value) => {
  setValues(values => ({ ...values, [name]: value }))
}

const { useState } = React;

functionApp() {
  const [values, setValues] = useState({});

  constdoSomething = (name, value) => {
    setValues(values => ({ ...values, [name]: value }));
  };

  return (
    <divonClick={() => doSomething(Math.random(), Math.random())}>
      {JSON.stringify(values)}
    </div>
  );
}

ReactDOM.render(<App />, document.getElementById("root"));
<scriptsrc="https://unpkg.com/react@16/umd/react.development.js"></script><scriptsrc="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script><divid="root"></div>

Solution 2:

Basically I would avoid mutating state in such way simply for the sake of purity.

However, I would argue that in this case it is perfectly fine. When you mutate a value in an inner level in the state it goes unnoticed by React. Only when calling setValues() with a new reference React notes to itself that a new render is pending.

const { useState } = React;

functionApp() {
  const [values, setValues] = useState({ num: 0 });

  consthandleClick = () => {
    doSomething();
    doSomething();
  }
  
  constdoSomething = () =>
    setValues((values) => {
      values.num += 1;
      return { ...values };
    });

return (
  <divonClick={handleClick}>
    {JSON.stringify(values)}
  </div>
);
}

ReactDOM.render( < App / > , document.getElementById("root"));
<scriptsrc="https://unpkg.com/react@16/umd/react.development.js"></script><scriptsrc="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script><divid="root"></div>

(If anyone can provide a counter example I would love to see it).

Post a Comment for "Mutating State From React's Usestate Hook"