Home > database >  Hook useState with useEffect
Hook useState with useEffect

Time:10-13

I encountered this behavior. Two onChange are called in turn. One of them saves data to the state, and use the previus state to generate new one.

const onChange = (data) => {
    setState1((prev) => {
      console.log("onChange set state");
      return [...prev, data];
    });
  };

The other just prints something to the console.

const onChange2 = (data) => {
    console.log("onChange2");
  };

onChange and onChange2 called after click on button

<button
        onClick={() => {
          onChange({ foo: "bar" });
          onChange2();
        }}
      >
        2
      </button>

useEffect - saves data to state

const [state, setState] = useState(0);
  const [state1, setState1] = useState([]);

  useEffect(() => {
    setState((prev) => {
      console.log("use effect set state");
      return prev   1;
    });
  }, []);

So, if you do not use useEffect (comment out), the console log, which in the first onChange will be called first, then the console log from the second onChange

enter image description here

enter image description here

If you uncomment useEffect, then the console will log from onChange2 first, then from onChange

enter image description here

enter image description here

Why is this happening, who can tell?

CodeSandBox: https://codesandbox.io/s/eager-hooks-sczvb

CodePudding user response:

The call order of onChange and onChange2 appear to change because the console.log in onChange is inside the callback passed to setState1.

If you move the console.log directly in the onChange you will see that the order is the same with or without useEffect.

const onChange = (data) => {
  console.log("onChange set state");
  setState1((prev) => {
    return [...prev, data];
  });
};

It's important to understand that when you call setState there is no guarantee that the state will be changed immediately, it's up to React to decide when to apply the new state and trigger a new render.

This is why the callback passed to setState should only return a new state and not run any effects (such as console.log) since the moment this code is run is considered in implementation detail and could change with any version of React.

CodePudding user response:

Expected behavior is onChange2 called first, and onChange set state called second whatever useEffect body is commented. because onChange2 called right now. but onChange set state in setState fn called after rendered。

The "bug" looked is why onChange set state called first when first click. Hmm... find react computeExpirationForFiber. setState callback execute sync or async by different conditions. It's hard to read.

  • Related