I have struggled with useEffect hook a couple of times recently. The reason why I struggled is mainly because useEffect
covers the side effects of not only componentDidMount
but also componentDidUpdate
and componentWillUnmount
. I come from class component based React, so it was very confusing at first.
The common misusages of useEffect
hook can result in:
- an infinite rendering of a component
- not updating the target states
- not rendering the components at all
Here are the three things you should know about useEffect
.
useEffect
runs after the first paint, not beforeuseEffect
runs after value changes in dependencies- Changes in both object and array states’ values cannot be detected
useEffect runs after the first paint
useEffect
runs after the first paint. So, for example, if you plan to set state value to an array of items from null
inside useEffect
, the first render uses the state value null
. Make sure that you will not try to iterate through the state value of null
on the first paint.
const [list, setList] = useState(null);
useEffect(()=> {
if(!list) {
setList(['item1', 'item2']);
}
}, []);
return (
<ul>
{
/* make sure that list is not set to null */
list && list.map(item => {
return <li>{item}</li>;
});
}
</ul>
);
useEffect runs after value changes in dependencies
The dependency array allows useEffect
to run every time the values are updated. The code below will set your component in an infinite loop of rendering since count
is set in the dependency array while being updated on every side effect.
const [count, setCount] = useState(0);
useEffect(() => {
setCount(count + 1);
}, [count]);
Re-rendering components with object and array states
Use the ES6 spread operator ...
to copy the existing items into the new array, and inserting the new item at the end. This way, React can detect changes in both object and array states by recognizing them as a new reference of object or array. Finally, the component re-renders by changes to the values of list
in the dependency array.
// example for array state
const [list, setList] = useState(null);
const [updateCount, setUpdateCount] = useState(0);
const handleAddItem = (e) => {
let item = e.target.value;
setList([...list, item]);
}
useEffect(()=> {
setUpdateCount(updateCount + 1);
}, [list]);
Thanks for reading.
Hope you enjoyed the article. If you have any question or opinion to share, feel free to write some comments.