1

I'm new with React and confused with the result below code is giving.
num gets value -1, where I think it should be 100.


useEffect[num] is expected to run first, calling setNum(100) since num is initialized to -1.
Then useEffect[dummy] will run, calling setNum(-1).

I learned that multiple calls to the same setState function are batched together, and only the result from the last call is rendered.

So it seems like setNum(100) will be overwritten by subsequent setNum(-1).

The problem is, if setNum(-1) was processed in the end, it should have called setNum(100) in useEffect[num].
num should be 100, but it's stuck at -1.

Why did my program stop before calling setNum(100) in the end?
Please teach me what I'm missing : async nature of setState or batched updates?

import "./styles.css";
import React, { useState, useEffect } from "react";

export default function App() {
  const [num, setNum] = useState(-1);
  const [dummy, setDummy] = useState(false);
  
  useEffect(() => {
    console.log("setNum : ", num);
    if (num === -1) setNum(100);
  }, [num]);

  // Just to call setNum(-1) separately
  useEffect(() => {
    console.log("Init dummy : ", dummy);
    setNum(-1);
  }, [dummy]);

  return (
    <div className="App">
      <div> {num} </div>
    </div>
  );
}

Here is codesandbox to run the code.
https://codesandbox.io/s/strange-chatelet-3oxy8?file=/src/App.js

0

3 Answers 3

2

The problem is, if setNum(-1) was processed in the end, it should have called setNum(100) in useEffect[num].

Here's how your code executes:

  1. Initial render of the component
  2. First useEffect is called; it logs the value of num and then calls setNum(100)
  3. Second useEffect is called which logs the value of dummy and then calls setNum(-1)
  4. There are two pending num state updates; both of them are batched and the last one wins, i.e. setNum(-1).
  5. Component re-renders and the value of num is -1 BUT that won't trigger the first useEffect, even though it depends on num, because the value of num didn't change; it's still -1

If you change the initial value of num to any value other than -1, you will see the first useEffect executing again like you expect.

Sign up to request clarification or add additional context in comments.

1 Comment

I am thinking that you explain my answer in detail and got the vote, xDD
1

If you switch the useEffects like this:

      // Just to call setNum(-1) separately
      useEffect(() => {
        console.log("Init dummy : ", dummy);
        setNum(-1);
      }, [dummy]);

      useEffect(() => {
        console.log("setNum : ", num);
        if (num === -1) setNum(100);
      }, [num]);

The final num should be 100.

1 Comment

So in this case, useEffect[dummy] calls setNum(-1) → useEffect[num] calls setNum(100) And last call 'setNum(100)' wins from batching
1

In the useEffect order matters and the initial value also.

If the initial value and settled value are the same then no rerender will execute and your dependency useEffect also not called and your final value will be your initial value.

export default function App() {
  const [num, setNum] = useState(-1);
  const [dummy, setDummy] = useState(false);

  useEffect(() => {
    console.log("setNum : ", num);
    if (num === -2) setNum(100);
  }, [num]);

  useEffect(() => {
    console.log("Init dummy : ", dummy);
    setNum(-2);
  }, [dummy]);

  return (
    <div className="App">
      <div> {num} </div>
    </div>
  );
}

For example, if you will add -2 in the if and your dummy useEffect then you will see your desire result 100.

Codesandbox: https://codesandbox.io/s/objective-blackwell-odl5v?file=/src/App.js

2 Comments

So if setState does not change the state, useEffect will not be called (neither rendering happens). Seems pretty obvious after reading this. Thank you for your answer!
Yes you are right, only the state can perform rerender, I am happy that you solved your confussion

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.