skip to Main Content

Is it correct that if a state is set to the same value as its initial value (like here we do setCount(1)), React will not trigger a re-render?
Regardless of the incorrect usage of the setCount in the render logic in the provided code snippet, I’m curious why it leads to infinite re-renders. This inquiry is solely for learning purposes.

function App(props) {
  const [count,setCount]=useState(1)

 setCount(1)
  return (
    <div className='App'>
      <h1>{count}</h1>
      <h2>Start editing to see some magic happen!</h2>
    </div>
  );
}

3

Answers


  1. It will re render infinitely ! See this stackblitz for confirmation : https://stackblitz.com/edit/stackblitz-starters-psegx9?file=src%2FApp.tsx

    The setX function always trigger a re-render (see https://react.dev/reference/react/useState#setstate). Thus you will have infinite rerenders since you call setCount on render.

    To avoid this and depending on your use case, you could use something like useMemo.

    Login or Signup to reply.
  2. It works like this when you run the code:

    1. variable count and setCount is initialised
    2. setCount is triggered (async)
    3. the components in your return are rendered
    4. the setCount function finished and count changed

      note: even though the value didn’t change, you assigned a new value (with a different memory address)
    5. react notices changes (count) and goes through your function again
    6. count/setCount is already initialised and is skipped
    7. step 2
    8. step 3

    That’s why you put it inside useEffect, which like usestate isn’t triggered each time a rerender occurs

    Login or Signup to reply.
  3. A react component has a certain lifecycle.
    enter image description here

    The lifecycle has certain phases, one of them being render:

    Now what is happening in the above code is that render phase is not being completed. It is being interrupted by setState which triggers another call, and queues a state update.

    React has a bailing behaviour, which helps it bails out of state updates based on certain conditions. This does not happen everytime though.

    Quote from docs:

    If you update a State Hook to the same value as the current state, React will bail out without rendering the children or firing effects. (React uses the Object.is comparison algorithm.) Note that React may still need to render that specific component again before bailing out. That shouldn’t be a concern because React won’t unnecessarily go “deeper” into the tree.

    Now the problem here is that a tree is not generated, and React has nothing to compare the previous and the current DOM structure.

    Look at the below code:

    function Test() {
      console.log({ child: true });
      return null;
    }
    
    function App() {
      const [count, setCount] = useState(1);
      console.log({ count });
      setCount(1);
      return (
        <div className="App">
          <Test />
        </div>
      );
    }
    export default App;
    

    {child:true} is never logged. Which means that even before the render phase is completed (and the tree build) the next render is triggered.

    Link to above sandbox

    When we put the above code inside a useEffect, React is able to diff between the two trees created.

    function App() {
      const [count, setCount] = useState(1);
      console.log({ count });
      useEffect(() => {
        setCount(1);
      });
      return (
        <div className="App">
          <h1>{count}</h1>
          <h2>Start editing to see some magic happen!</h2>
        </div>
      );
    }
    

    Now, even if we are essentially doing the same thing as earlier but because we are letting the tree being created, React is able to bail out of state update.

    Link to above sandbox

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