Reputation: 467
This piece of code will run infinitely, but no matter removing the useValue(object)
or useTest()
will stop the infinite run. This whole thing does not make sense to me, can somebody explain it?
https://codesandbox.io/s/zen-currying-v2zu1?file=/src/App.js
import React from "react";
import { useEffect, useState } from "react";
import "./styles.css";
export default function App() {
// this code can also stop the infinite loop
// const [object] = useState({
// name: "",
// personId: ""
// });
const object = {
name: "",
personId: ""
};
// strange thing: remove useValue or useTest can stop the ifinite loop
useValue(object);
useTest();
// this console will run infinitely
console.log(object);
return <div className="App">{"123"}</div>;
}
export const useTest = () => {
const [a, setA] = useState(1);
useEffect(() => {
setA(2);
}, []);
};
const useValue = (value) => {
const [a, setA] = useState(value);
useEffect(() => {
setA(value);
}, [value]);
// return a
};
Upvotes: 0
Views: 585
Reputation: 1103
Because object
is a reference type, its identity will change every time you rerender App
. There you use a custom hook useValue
and pass object
into it. Since you also register it as value
in the dependency array of useEffect
, useEffect
will be triggered, setting a new state, ending in rerendering and looping.
useMemo
or useCallback
).useEffect
. Its behaviour strongly depends on how you use its dependency array.Upvotes: 1
Reputation: 562
Because you passed an object in the dependencies. useEffect with do a shallow comparison so it always renders.
There are some solutions. Read here. You could modify your useValue hook to use JSON.stringify as below.
const useValue = (value) => {
const [a, setA] = useState(value);
useEffect(() => {
setA(value);
}, [JSON.stringify(value)]);
// return a
};
Upvotes: 1
Reputation: 3244
Make sure to memoize your object in order to properly use it in dependencies.
const { useMemo } from 'react';
const object = useMemo(
() => ({
name: "",
personId: ""
}),
[]
);
The reason behind the infinite loop is because you're providing a non-memoized object into your dependency array in useEffect
.
Object comparison in Javascript is more complex than just comparing obj1 === obj2
, as there is a reference that needs to be taken into account.
Read more about comparing objects in javascript here
Upvotes: 1