Reputation: 169
somehow I got an infinity loop, the weird situation that I did solve it but I got a warning and I wish to fix the warning.
this is code that work:
import { ArrowDropDown, ArrowRight } from "@material-ui/icons";
import React, { useState, useEffect, useCallback } from "react";
import "./tree.css";
const Tree = ({ explorer }) => {
const [expand, setExpand] = useState(true);
const [arrow, setArrow] = useState(false);
const stateHandler = () => {
setExpand(!expand);
setArrow(!arrow);
};
useEffect(() => {
//this function will display only the first Tree as init the page.
stateHandler();
}, []);
return (
<div>
<div className="treeInfo">
{arrow ? (
<ArrowDropDown className="treeIcon" />
) : (
<ArrowRight className="treeIcon" />
)}
<span className="treeTitle" onClick={stateHandler}>
{explorer.name}
</span>
</div>
<div
style={{
display: expand ? "block" : "none",
paddingLeft: 20,
cursor: "pointer",
}}
>
{explorer.items.map((explore) => {
return <Tree key={explore.id} explorer={explore} />;
})}
{/* {explorer.items.map((explore) => (
<Tree explorer={explore} />
))} */}
</div>
</div>
);
};
export default Tree;
and this is the warning:
src\components\Tree\Tree.js
Line 17:6: React Hook useEffect has a missing dependency: 'stateHandler'. Either include it or remove the dependency array react-hooks/exhaustive-deps
Search for the keywords to learn more about each warning.
To ignore, add // eslint-disable-next-line to the line before.
WARNING in src\components\Tree\Tree.js
Line 17:6: React Hook useEffect has a missing dependency: 'stateHandler'. Either include it or remove the dependency array react-hooks/exhaustive-deps
webpack compiled with 1 warning
**
**
well as I can read I got this warning because useEffect got not dependencies, when I add the stateHandler dependencies I got an infinity loop, so I add a callback function but it still doesn't solve the infinity loop. this is the code with the useCallback (its the same code, just with useCallback and a bit of configure of the useEffect):
const initTree = useCallback(() => {
setExpand(!expand);
setArrow(!arrow);
}, [setExpand, setArrow, arrow, expand]);
useEffect(() => {
//this function will display only the first Tree as init the page.
initTree();
}, [initTree]);
Upvotes: 3
Views: 664
Reputation: 3860
You need to change this:
const initTree = useCallback(() => {
setExpand(!expand);
setArrow(!arrow);
}, [setExpand, setArrow, arrow, expand]);
to this:
const initTree = useCallback(() => {
setExpand(e => !e);
setArrow(a => !a);
}, []);
Otherwise what happens is this:
initTree
variable is initialized with a function, the Effect
is run and setExpand
and setArrow
are called.useCallback
hook checks if the deps of initTree
have changed and yes, arrow
and expand
have changed indeed, hence initTree
variable is updated with a new functioninitTree
has changed from the previous render, and yes, it has changed, hence the effect executes again calling initTree
again.Eslint shouldn't complain of missing deps if you don't put the setState
in deps, since they do not change during renders, unless you are passing them through props.
Upvotes: 5
Reputation: 1715
If you are ok with having another state, you can simply set something like a loading
state and make the useEffect depend on that
State would look like this:
const [expand, setExpand] = useState(true);
const [arrow, setArrow] = useState(false);
const [loading, setLoading] = useState(true);
And then based on this, useEffect would change as follows:
useEffect(() => {
//this function will display only the first Tree as init the page.
stateHandler();
setLoading(false);
}, [loading]);
Once loading is set to false, it's value is not going to change and the useEffect will not be triggered indefinitely
Upvotes: 1