Yesterday, while working on this project, I came to realise that logic contained in useFetchCollections
was flawed in that it was invoked endlessly.
This had for perverse effect that the free daily allowed quota in firestore
was reached !
Read access to the cloud database was forbidden for almost 24 hours !!!!
Therefore, to fix this, I pushed a commit that :
1) fixes the endless loop, and
2) now makes use of collections
data from a local json file instead of fetching it from the database (using process.env.NODE_ENV
the code determines whether the environment is production
or development
in order to conditionally fetch this data set in one data source or the other)
The useEffect
hook tribulations
This loop happened because the data fetching was inside a useEffect
hook, as seen in this file history:
const fetchCollections = fetchCollectionsAsync(setCollectionsState);
useEffect(() => {
fetchCollections();
}, [fetchCollections]);
return collectionsState;
};
The problem was to have included fetchCollections
as a dependency inside the array (the second argument that useEffect
takes). Without its inclusion there, the React lib issued a warning :
React Hook useEffect has a missing dependency: `fetchCollections`.
Either include it or remove the dependency array.
If `fetchCollections` changes too often, find the parent component that defines it and wrap that definition in useCallback
In this particular issue, I needed to ensure that useEffect
fired only once, so the fix I issued is as follows:
useEffect(() => {
fetchCollectionsAsync(setCollectionsState);
}, []);
The fix allowed to:
A) get rid of the React warning, and
B) get useEffect
to behave as needed by providing an empty dependency array, to have it fire only once in the whole component lifecycle.
When NOT to pass array of dependency to useEffect
One of the suggestions found in the warning message was to remove the dependency array
.
After some research, it turns out that we must omit this array of dependency when we want useEffect
to trigger:
- everytime the component it is in has finished rendering
-
whenever
useEffect
is invoked
Reminder about component rendering
A component will re-render when either:
- props change
- state change
- the parent component re-renders
useEffect
Cheat Sheet
Even though Dan Abramov, the lead dev in the React team will not like it, here is a cheat sheet which "maps" useEffect
use cases in terms of Class-based component lifecycles.
ComponentDidMount
//Class
componentDidMount() {
console.log('I just mounted!');
}
//Hooks
useEffect(() => {
console.log('I just mounted!');
}, [])
ComponentWillUnmount
//Class
componentWillUnmount() {
console.log('I am unmounting');
}
//Hooks
useEffect(() => {
return () => console.log('I am unmounting');
}, [])
ComponentWillReceiveProps
//Class
componentWillReceiveProps(nextProps) {
if (nextProps.count !== this.props.count) {
console.log('count changed', nextProps.count);
}
}
//Hooks
useEffect(() => {
console.log('count changed', props.count);
}, [props.count])
Top comments (0)