Welcome back to our React Series. I want to believe you had a good grasp of the useState hook in the last class. There is so much more hooks will do for you, and I believe as you continue with this series, you will learn a lot more about them. Today we are moving on to another important hook that you will always come across in your journey in React, and that is the useEffect hook.
What is useEffect hook?
According to the React documentation, the useEffect hook was developed to eliminate some of the challenges posed by the life cycle methods of ES6 class components. The main challenge being handling side-effects. When you create an application that updates user information at every click or a timer app using setTimeout(), this can lead to some unwanted side-effects, and that's one use-case for useEffect.
Using useEffect is understanding the lifecycle of a component. A component's lifecycle is in three stages: componentDidMount, componentDidUpdate and componentWillUnmount. Albeit, using these lifecycle methods is a class component feature. They cannot be used in a functional component.
useEffect is a combination of React's lifecycle methods. It helps you eliminate the repetition of code, and groups related code in one code block in a functional component. With useEffect, you can do so much with writing so little.
Important concepts about useEffect
It handles side-effects.
It takes in 2 arguments: a callback function and a dependency array.
The dependency array can take in more than one variable.
Effects automatically run after every re-render, except you handle it in your dependencies.
If handled in the dependency, effects run only when there is a change in the state of the dependency.
If not handled well, side-effects can have damaging effects on your program or code.
It helps you recognize the relevant part of the code after the first render.
What are side-effects?
These are actions performed outside of our React component in the component. These actions can indirectly change the returned output of our React component. Usually, the output of a component should be determined by the props or state. Side-effects are used to communicate with elements outside of the component. These elements can be APIs for data fetching, manually changing the DOM, and timer functions like setTimeout, window objects etc.
How to use useEffect
At this point, I believe you already have some sort of insight as to the use of useEffect. Now, we will be moving on to how to write your first useEffect.
As I mentioned in the earlier point stated above, useEffect takes in two (2) arguments: a callback function and a dependency array. Let's see what that looks like in the code.
import { useEffect } from 'react'
useEffect((callback) => {
//function that runs every time there is a re-render.
}, [dependency array])
Typically, this is how to write your useEffect. Takes in two (2) arguments: the callback function and the dependency array. If there is any type of change in the dependency variables, the callback function runs automatically. The dependency array could be a variable, prop or some kind of state. Also, the dependency array could contain more than one item. It can take in as many variables as possible.
useEffect With An Empty Depencendy Variable:
import { useEffect } from 'react'
useEffect((callback) => {
//function that runs every time there is a re-render.
}, [])
When the dependency variable is empty, the callback function runs only once, and that is when the component renders for the first time.
useEffect Without a Dependency Array:
When the dependency array is not included in the useEffect, the function for the side-effect runs every time there is a re-render. Doing this might lead to multiple re-renderings and that may be bad for your program.
import { useEffect } from 'react'
useEffect((callback) => {
//function that runs every time there is a re-render.
})
Cleanup Function in useEffect?
We sometimes need to stop the side-effect from running in a program. If for example, we have a timer function using setInterval, the function will keep running until we stop the function using clearInterval. Another example can be subscriptions that need to be stopped when they are no longer required. Cleanup function allows us to stop side-effects that no longer need to be run.
If for example we set state using setInterval and the function was not cleaned up. When the component is abandoned or no longer in use, the setInterval function will keep running and it will try to update the state even though it no longer exists. That is what we call Memory Leak. An example is in the code below.
import React, {useState, useEffect} from 'react'
const Test = () => {
const [time, setTime] = useState(0);
useEffect(() => {
setInterval(() => setTime(time + 1), 5000);
console.log(time);
}, []);
}
export default Test
The above code is to update by 1 every 5 seconds. Even when we abandon the component and don't use it again, under the hood, it will keep incrementing, and that's because we didn't do a cleanup which may eventually cause a problem in our application.
To cleanup our timer function, we will create a clearInterval function under the callback. This clearInterval function will cleanup the side-effect every time our timer function runs. Let's see the code below.
import React, {useState, useEffect} from 'react'
const Test = () => {
const [time, setTime] = useState(0);
useEffect(() => {
let interval = setInterval(() => setTime(time + 1), 5000);
return () => {
// setInterval is cleared when component unmounts
clearInterval(interval);
}
}, []);
}
export default Test
With this cleanup function, we are guaranteed that this component can do no damage to our application, because once the component unmounts, the side-effect stops updating.
NOTE:
You do not need the cleanup function for every side-effect. You only use it for certain components that update every time like a timer function, subscription etc.
I really hope this was helpful. If you have any questions, please feel free to ask me anytime. Also, don’t forget to follow me and like this tutorial.
Thanks and have a great weekend.