skip to Main Content

I’m a beginner in React.js, and I was reading this article:

https://blog.logrocket.com/solve-react-useeffect-hook-infinite-loop-patterns/

There, there’s this code:

function App() {
  const [count, setCount] = useState(0);
  useEffect(() => {
    setCount((count) => count + 1);
  }, []);
  return (
    <div className="App">
      <p> value of count: {count} </p>
    </div>
  );
}

This is the code from the site, to which I’ve added the dependency array.
It shows a useEffect code that should print the value of 1 on the screen.
However, here on my side the printed value is 2.
Also, if I try the following (same code, but logging "count" value to the console):

function App() {
  const [count, setCount] = useState(0);
  useEffect(() => {
    setCount((count) => count + 1);
  }, []);
  useEffect(() => {
    console.log(count);
  }, [count]);
  return (
    <div className="App">
      <p> value of count: {count} </p>
    </div>
  );
}

The logged values are 0, 0 and 2. What explains this weird behaviour? Shouldn’t it just print the value of 1 in the console (first useEffect triggers once, followed by the second useEffect triggering once?)?

2

Answers


  1. Chosen as BEST ANSWER

    The "weird" behaviour was being caused by Strict Mode.


  2. The behavior you’re observing is due to how the useState and useEffect hooks work in React. Let’s me break down the code for your understanding:

    In your first example

    function App() {
      const [count, setCount] = useState(0);
      useEffect(() => {
        setCount((count) => count + 1);
      }, []);
      return (
        <div className="App">
          <p> value of count: {count} </p>
        </div>
      );
    }
    

    The useEffect with an empty dependency array [] is executed after the initial render, and it increments count by 1. This means that count should be 1 after the first render. However, since the setCount function is asynchronous, it doesn’t immediately update the value of count inside the same render cycle. So, you see 0 during the render, and after the update, it becomes 1.

    In your second example:

    function App() {
      const [count, setCount] = useState(0);
      useEffect(() => {
        setCount((count) => count + 1);
      }, []);
      useEffect(() => {
        console.log(count);
      }, [count]);
      return (
        <div className="App">
          <p> value of count: {count} </p>
        </div>
      );
    }
    

    The first useEffect runs as before and sets count to 1. The second useEffect has a dependency on count, so it logs the current value of count, which is 0, after the first render. Then, since count changes, it logs the updated value, which is 2, after the second render.

    In both cases, count is correctly updated to 1, but it’s only reflected in the component’s render after the initial render. This behavior is due to the asynchronous nature of state updates in React.

    If you want to ensure that the updated count is logged immediately after it’s incremented, you can use the useEffect with an empty dependency array for logging, like this:

    useEffect(() => {
      console.log(count);
    }, []);
    

    In this way, it will log the updated value immediately after the state change.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search