What is a useEffect Hook?
TL;DR
React
useEffectis an alternative to the "old"classlifecycle methods/hooks. It is used to manage side effects, such as network requests or run a piece of code when the component is mounted, updated, or unmounted.
Longer version
Before
React v16.8, we can only enable a component to react to state changes using lifecycle methods.
How to define a useEffect
.jsx
1useEffect(() => { //(1) declaration2 // (2)effect3 return () => {4 // (3)cleanup 5 }6}, /* (4)dependency array */)Here's a quick explanation of the above code:
- We can declare an effect by calling either
React.useEffectoruseEffect. effectis the function that will be called when the component is mounted. OR when the dependency array changes.cleanupis the function called when the effect is "unmounted".dependency arrayis the array of values passed as a second argument to theeffectfunction.- If there is no dependency array, the effect will be called every time the component is mounted.
- If the array is empty, the effect will be called only once when the component is mounted.
- If the array is not empty, the effect will be called every time the component is mounted and the dependency array changes.
Examples
Increment a counter every second until it reaches 10
.jsx
1function App() {2 const [count, setCount] = useState(0)3
4 useEffect(() => {5 if (count < 10) {6 const interval = setInterval(() => {7 setCount(prev => prev + 1)8 }, 1000)9
10 // cleanup function11 return () => clearInterval(interval)12 }13 }, [count])14
15 // Render the component16}Basic fetch from an API
.jsx
1function App() {2 const [data, setData] = useState([])3
4 useEffect(() => {5 fetch('https://jsonplaceholder.typicode.com/users')6 .then(res => res.json())7 .then(data => setData(data))8 }, [])9
10 // Render the component11}Fetching with loading indicator + error handling - then/catch/finally
.jsx
1function App() {2 const [data, setData] = React.useState()3 const [error, setError] = React.useState()4 const [isLoading, setIsLoading] = React.useState(false)5
6 React.useEffect(() => {7 setIsLoading(true)8
9 fetchData()10 .then(data => {11 setError(null)12 setData(data)13 })14 .catch(data => {15 // handle error case anyway you want16 setError(data)17 setData(null)18 })19 .finally(() => setIsLoading(false))20 }, [])21
22 // Render the component23}Fetching with loading indicator + error handling - async/await
.jsx
1function App() {2 const [data, setData] = React.useState()3 const [error, setError] = React.useState()4 const [isLoading, setIsLoading] = React.useState(false)5
6 React.useEffect(() => {7 // yeah, this is weird8 (async () => {9 try {10 setIsLoading(true)11 const data = await fetchData()12 setError(null)13 setData(data)14 } catch(e) {15 // handle error case anyway you want16 setError(e)17 setData(null)18 }19 setIsLoading(false)20 })()21 }, [])22
23 // Render the component24}Store a value in localStorage everytime the key or value changes
.jsx
1function App({ name }) {2 const [value, setValue] = useState(() => localStorage.getItem(name))3
4 useEffect(() => {5 localStorage.setItem(name, value)6 }, [name, value])7 // Ignore old keys for now8
9 // Render the component10}OR mimic a class lifecycle method
Check this blog on how to convert a class lifecycle methods to
useEffecthooks
Additional Note
useEffectcan only be used in functional components- The order of
useEffectdeclarations is important. useEffectin a custom hook is a great way to promote side effect reusability. I will discuss this in another blog.
Conclusion
Compared to the old lifecycle methods, useEffect is much more powerful and flexible, making it an ideal choice when managing a side-effect.
