4

Hi I'm learning React now and having trouble with the state..

I know when the state changes, the component re-renders and the code in UseEffect widout depth only runs once. But I can't explain exactly why infinite rendering occurs when I write setState in JSX or in the render syntax.

below code causes infinite re-render

import React, { useState, useEffect } from 'react'

const index = () => {
  const [active, setActive] = useState(false);
  console.log("render", active);
  setActive(false);
  
  return (
    <div>
      
    </div>
  )
}

export default index

But the code below has no problem even though it keeps calling setState.

import React, { useState, useEffect } from 'react'

const index = () => {
  const [active, setActive] = useState(false);
  console.log("render", active);

  useEffect(() => {
    setInterval(()=>{
      console.log("run")
      setActive(true)
    },0);
  }, [])
  
  return (
    <div>
      
    </div>
  )
}

Does setState trigger re-rendering regardless of state value? I want to know the exact reason why using setState outside of useEffect causes an error.

minami
  • 207
  • 3
  • 13
  • It looks like this is related to component lifecycle; the first example runs `setActive` before rendering at which time the cycle can be aborted or restarted by React, while the second example calls it after rendering is complete at which time React is better able to avoid unnecessary rerenders – pilchard Aug 20 '21 at 11:04
  • Does this answer your question? [Difference between with and without useEffect in react functional component](https://stackoverflow.com/questions/62653595/difference-between-with-and-without-useeffect-in-react-functional-component) – pilchard Aug 20 '21 at 11:06

2 Answers2

1

This is happening because, in the first case, when useEffect is not used, you are updating your state right after declaring it. Even if you are setting the state as false again, but for react, the state has been updated. And the first rule of thumb for react is, if state update happens, component will re render.

This is why you are getting an infinite rerendering.

your code is following the below flow:

  1. Declare state variable and pass value as false
  2. Update state to false
  3. State updated, hence component re rendered.
  4. Step 1 again.

In second case, where use effect is used, your state will update only when the component is mounted, which means, after that any state update won't trigger your useEffect.

  • 1
    _"your state will update only when the component is mounted"_ - inside the `useEffect`, there is `setInterval` call which calls `setActive(true)` at regular intervals. Why isn't the component re-rendering everytime `setActive(true)` is called? Reason is, if the old state and previous state are same, react will bail-out of the state update and NOT re-render the component BUT, as mentioned in the answer below, React may need to render the component again before bailing out of state update. – Yousaf Aug 20 '21 at 12:47
0

Based on React documentation: https://reactjs.org/docs/hooks-reference.html#usestate

The setState function is used to update the state. It accepts a new state value and enqueues a re-render of the component.

And there is an addition: https://reactjs.org/docs/hooks-reference.html#bailing-out-of-a-state-update

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.

And here is the important part: React may still need to render that specific component again before bailing out.

So yes, the component may still rerender even if the values are the same.

dsdenes
  • 1,025
  • 6
  • 15
  • 1
    If you wrap `setActive` call in `setTimeout(...)`: `setTimeout(() => setActive(false), 0)`, then React bails out of state update as expected; still not sure why React doesn't bails out with `setActive` call at the top-level of the function component – Yousaf Aug 20 '21 at 10:56