React UseEffect As Lifecycles
If you ever check a react codebase with functional components, you’ll notice two words used widely in the project. useState and useEffect. Of course if the components are functional. The work of useState is simple, creates a state and re-renders a component when it changes. But useEffect is something very strange behind the scenes. It is used for any operations while rendering a component. Such as, third party API calling, changing a state value while rendering a component etc.
But useEffect does something more behind the scenes. For the functional components, it works as a substitute to the lifecycle methods, which are only available for class components. And that’s where the confusion occurs. A lot of developers use useEffect hook just to run an operation while rendering components. Here, I will describe how useEffect runs the lifecycle methods behind the scenes.
The useEffect hook
The useEffect hook does the operation of three component lifecycle methods in a body. componentDidMount, componentDidUpdate and componentWillUnmount. But, we need to have ideas about those.
componentDidMount
componentDidMount is a lifecycle method where the component is created and inserted to the DOM. It runs when the component mounts. Here we can make API calls, changing state etc.
componentDidMount() {
this.setState({
loading: false
})
}
componentDidUpdate
componentDidUpdate runs whenever a component updates. It takes the previous props and states as properties and runs if there is a mismatch between current and previous states and props.
componentDidUpdate(prevProps, prevStates){
if(this.props.loading !== prevProps.loading){
return true
}
}
You can decide whether you can update based on the change of props and/or states.
componentWillUnmount
This lifecycle runs right before the component is unmounted. Here all the subscriptions are cancelled, all the networks are disconnected and all the timers are cleared. In a nutshell, all the cleanup works are occurred in componentWillUnmount
componentDidMount(){
this.interval = setInterval(()=>{
this.setState({
seconds: seconds + 1
})
},1000)
}
componentWillUnmount(){
clearInterval(this.interval)
}
You can see that I ran a setInterval which increases the state “second” by 1 in every second inside componentDidMount. And in componentWillUnmount, the interval is cleared.
The useEffect hook
The useEffect hook takes two arguments. A callback function which is a must, and a dependency array which is optional. But the use of the dependency array will decide which lifecycle hook is actually running behind the scenes of useEffect.
But first let’s talk about the use of the dependency array.
- If you don’t provide the dependency array in the useEffect, the hook runs on every render.
- If you provide an empty dependency array, the hook will run on initial render, because there’s nothing to be updated inside the component.
- If you provide a dependency array with one or more elements, the effect will run based on the change of at least one of the elements.
useEffect with componentDidMount
You can run useEffect only once when you mount the component, if you want the useEffect to function like componentDidMount. Here the effect will just run when the component mounts. To do this, just remove the dependency array.
useEffect(()=>{
setLoading(true)
})
If there is no dependency array, the effect will run whenever the component updates. It will still work as componentDidUupdate lifecycle. Because, every time a component updates it re-renders. And without a dependency array, useEffect will run on every mount and render.
useEffect with componentDidUpdate
You can at least one element in a dependency array to run effect on every update on the dependency array elements. Which means if any of the elements of the dependency array updates then the effect will run.
useEffect(()=>{
if(!loading){
setRun(true)
}
}, [loading])
Here, whenever the value of loading changes, the effect runs.
Whenever a component updates, the effect will look at the dependency array. And if there is any change in the elements, the effect will run.
useEffect with componentWillUnmount
This time we will kill the component with useEffect. And we just need to return a function from the callback.
useEffect(()=>{
setRun(true)
return ()=>{
console.log("component will unmount")
}
})
When you return a function from the callback of the effect, React will run it when it is time to unmount the component.
Conclusion
useEffect is one of the most confusing but essential topics in React. It runs three lifecycle methods under the hood. It is the substitute to lifecycle methods in functional components. React introduced this hook so that they can run effects based on fresh values. Also, reducing the complexity of the code by running three methods in only one hook function.