FaiChou
FaiChou

Reputation: 837

Why setState(hook) in function component cause an infinite loop?

Here is the code:

import React, { useState } from 'react'

function App() {
  const [a, setA] = useState(1)
  setA(2)
  return (
    <div>
      <h1>{a}</h1>
    </div>
  );
}

Error. Too many re-renders. React limits the number of renders to prevent an infinite loop.

Why it can cause an infinite loop?

I think the reason is that function component just as a render function, so it will cause infinite loop when setState in render functions.

Is there any official explanation?

Upvotes: 5

Views: 5184

Answers (5)

Yurii Brusentsov
Yurii Brusentsov

Reputation: 577

Because calling setA(2) causes the component to re-render.

Upvotes: 0

Praveen Patel
Praveen Patel

Reputation: 1189

const [rows, setRows] = useState([]);
return {
<Component data= {someData}
           selectCallback ={ (rows) => {
                        console.log(rows);
                        setRows(rows); // if set State going infinity loop
}}
...remainProps
/>

Its giving infinity loop when trying to setState and if we didn't use the setRows then in console giving right answers means array of objec

Help appreciated.

Upvotes: 0

Sohail Ashraf
Sohail Ashraf

Reputation: 10569

On each state update React will re-render the component and run all the function body, as the setA(2) is not enclosed in any hook or function and is a part of the function/component body. React will execute this on each render cycle. This make an infinite loop.

On Component mount React will set the state and go for the component update as the state updated, again there is state update React will again re-render the component. This cycle will continue until react reaches the re-render limit.

You could avoid this by wrap the state update in hook.

import React, { useState } from 'react'

function App() {
  const [a, setA] = useState(1)
  useEffect(() => {
    setA(2)
  },[]);
  
  return (
    <div>
      <h1>{a}</h1>
    </div>
  );
}

Upvotes: 5

Olivier Boiss&#233;
Olivier Boiss&#233;

Reputation: 18083

When calling setA you actually update a state variable and trigger a re-render of you component.

When the component re-render it will call setA (just before the rendering) and will trigger a re-render again.

Can you see the infinite loop ?

Traditionally you update a state variable into a callback (i.e when the user click on a button) or under certains conditions.

In your example, you can directly set a to 2

function App() {
  const [a, setA] = useState(2)
  return (
    <div>
      <h1>{a}</h1>
    </div>
  );
}

If you want to have the first render with a = 1, then immediatly have a = 2, you can use an effect which will be executed only once (because of the empty array for the second argument)

function App() {
  const [a, setA] = useState(2)
  useEffect(() => setA(2), [])

  return (
    <div>
      <h1>{a}</h1>
    </div>
  );
}

Upvotes: 3

izambl
izambl

Reputation: 659

Because you are setting a new value to the state with setA(2), so each time the component is rendered the state receives a new value, forcing the component to render again

Upvotes: 0

Related Questions