Considering such code below:
const [list, setList] = useState([]);
const [curPage, setCurPage] = useState(0);
const fetchItem = useCallback(async ()=>{
const data = await callAPI(); // data is an object
setList(prev => [...prev, data]);
},[]);
useEffect(()=>{
if(list.length - 1 < curPage) {
fetchItem().then(()=>{
// some operations
});
} else {
// some operations
}
},[curPage, fetchItem]); // eslint will throw a warning: React Hook useEffect has a missing dependency: 'list.length'. Either include it or remove the dependency array. (react-hooks/exhaustive-deps)
ESlint will throw a warning because I didn’t put list
in dependencies array, but it was used in the effect.
But if I put list
or list.length
in dependencies array, the effect will execute repeatedly because the fetchItem
will update list
.
I tried to add a ref
to store list.length
, but I think it’s unconventional.
Is there any better and elegant way to handle this kind of situations when an effect depends on a state which will update during the execution of the effect?
2
Answers
To execute your code when a component mounts, you need to write it in the body of useEffect. Additionally, if you want your code to be executed when the component updates, you should specify the dependencies that trigger its execution. When any of the dependent values change, the code inside useEffect will run again.
you can test this code :
You’ll need to add a check within
useEffect
to see if the fetch is necessary and, if not, exit without fetching again. You can store information about the last fetch and then use that in the condition.For example:
Note that I’ve used a ref for
lastFetchedPageRef
because updating that value doesn’t need to cause a rerender.