This code below produces an infinite loop, maxing out the rendering.
I’m unsure why this is happening.
We have a similar problem in our enterprise codebase that has been resolved by changing the constant array to a state variable so it doesn’t always change and by removing it from the useEffect because it won’t change.
I’m guessing that by setting y, a different variable, to a constant array, it causes a rerender and x changes because the pointer value changes?
I’m not sure but I find this behavior odd.
import React, { Component, useState, useEffect, useCallback } from 'react';
import { render } from 'react-dom';
import Hello from './Hello';
import './style.css';
const App = (props) => {
const [y, setY] = useState([]);
const x = [1001, 1002];
setY(x);
useEffect(() => {
console.log(x);
}, [x]);
return <div></div>;
};
render(<App appName="User Details" />, document.getElementById('root'));
2
Answers
The infinite loop in your code is caused by incorrect usage of the
useState
hook and thesetY
function.In React, the
useState
hook returns an array with two elements: the current state value and a function to update that state value. When you callsetY(x)
, you’re trying to update the state value ofy
tox
. However, sincex
is a constant array[1001, 1002]
, it cannot be updated. Instead, you should initializey
with the initial value ofx
:Additionally, in your
useEffect
hook, you have specifiedx
as a dependency. This means that the effect will run wheneverx
changes. However, sincex
is a constant array that doesn’t change, the effect will run indefinitely, causing the infinite loop.To fix this, you can remove
x
from the dependency array, or if you want to log the initial value ofx
once, you can pass an empty dependency array ([]
) to ensure the effect runs only once when the component mounts:Here’s the updated code:
With these changes, the code should no longer result in an infinite loop and excessive rendering.
The truth is exactly the opposite from what @Anubhav Raj suggests.
Each time your component renders, x is an entirely new array by reference. And you are calling
setY
with it without any kind of wrapper (usually you’ll call these setters inuseEffect
or a callback you create withuseCallback
, but in this case it doesn’t matter because it will always happen on every render anyway).Think of it this way:
These are two different Array objects, even though the elements of both are the same. The fact that this is happening in two different runs of the same function makes it difficult to reason about, but essentially the same thing is happening.
Because you’re calling
setY
with that new value, that queues up a rerender, causing the whole process to happen again.Check out this post for more info.