Trí Phan
Trí Phan

Reputation: 1193

React Hooks state not working properly when the function calling it is called in another function

I have this component using Hooks:

function App() {
  const [text, setText] = useState({ h1: "hello", h2: "hi" });

  const changeH1 = () => {
    setText({
      ...text,
      h1: text.h1 + "C"
    });
  };

  const changeH2 = () => {
    setText({
      ...text,
      h2: text.h2 + "X"
    });
  };

  const changeAll = () => {
    changeH1();
    changeH2();
  };

  return (
    <div className="App">
      <h1 onClick={() => changeH1()}>{text.h1}</h1>
      <h1 onClick={() => changeH2()}>{text.h2}</h1>
      <button onClick={() => changeAll()}>Change</button>
    </div>
  );
}

It will display two headings with some text and a button. When I click on the first heading, the "C" character will be added to the heading. When I click on the second heading, the "X" character will be added to the heading. When I click the button, it will do two actions above at the same time.

It works fine on two headings but the button. When I click the button, only the second heading changes. I think that the setText of changeH1 and changeH2 are not working when they are called in changeAll. What's wrong with my code?

Upvotes: 3

Views: 1470

Answers (1)

Aprillion
Aprillion

Reputation: 22304

Because changeH2() overwrites h1 property by doing ...text.

The 2 setText() calls are executed before a re-render - I believe it's due to batching as explained in https://overreacted.io/react-as-a-ui-runtime/#batching

A solution would be to use a simple state instead of an object:

  const [h1, setH1] = useState("hello");
  const [h2, setH2] = useState("hi");
  ...

Or else useReducer for more complex operations https://reactjs.org/docs/hooks-reference.html#usereducer

Upvotes: 1

Related Questions