Borislav Hadzhiev
Tue Apr 19 2022·2 min read
Photo by Sasha Freemind
Use the useEffect
hook to listen for state changes in React. You can add the
state variables you want to track to the hook's dependencies array and the logic
in your useEffect
hook will run every time the state variables change.
import {useEffect, useState} from 'react'; const App = () => { const [count, setCount] = useState(0); useEffect(() => { console.log('useEffect ran. count is: ', count); }, [count]); // 👈️ add state variables you want to track return ( <div> <button onClick={() => setCount(count + 1)}>Increment</button> </div> ); }; export default App;
The second parameter we passed to the useEffect hook is an array of dependencies. The function we passed to the hook will get invoked any time one of the dependencies changes.
We added the count
state variable to the hook's dependencies array, so any
time count
changes, the logic in our useEffect
hook will re-run.
useEffect
hook.Note that the hook is also invoked when the component mounts.
If you don't want to run the logic in your useEffect
hook on the initial
render, but only when the specific state variable changes, use a ref
to return
early on the initial render.
import {useEffect, useRef, useState} from 'react'; const App = () => { const [count, setCount] = useState(0); const isFirstRender = useRef(true); useEffect(() => { if (isFirstRender.current) { isFirstRender.current = false; return; // 👈️ return early if first render } console.log('useEffect ran. count is: ', count); }, [count]); // 👈️ add state variables you want to track return ( <div> <button onClick={() => setCount(count + 1)}>Increment</button> </div> ); }; export default App;
We used a ref to exit
early when the useEffect
hook is ran on mount.
Use this approach if you want to listen for state changes but need to skip the first render.
It should be noted that if you update a specific state variable in the
useEffect
hook and the variable is present in the hook's dependencies array,
you would cause an infinite re-render loop.
Here is an example that demonstrates this issue.
import {useEffect, useState} from 'react'; const App = () => { const [count, setCount] = useState(0); useEffect(() => { console.log('useEffect ran. count is: ', count); setCount(count + 1); // 👈️ this causes infinite loop }, [count]); return ( <div> <button onClick={() => setCount(count + 1)}>Increment</button> </div> ); }; export default App;
The issue is that we have added the count
state variable to the dependencies
array of the useEffect
hook, but we are also updating count
in the hook.
Every time useEffect
is ran, the value for the count
variable is changed,
which re-runs the hook again because count
is in its dependencies array.