useEffect
Hook with lifecycle methodsEditor’s Note: This post was updated on 17 March 2022 to update any outdated information as well as update the Using componentDidMount
in functional components with useEffect
section and the Updating phase with shouldComponentUpdate
and componentDidUpdate
section.
React has brought us a few different concepts like the virtual DOM, for instance. It also introduced different libraries and new ways of solving problems that we might face in development.
With this, we’re always improving our code to create more maintainable and well-written applications. But, one of the most important features of React (that is built into the React core itself) is the React component’s lifecycle and the lifecycle methods.
So, in this post, we’ll cover:
useEffect
to apply lifecycle methods in functional components
One of the most important features that React introduced to us was the virtual DOM, which lets us easily replace a specific element in the DOM by using the virtual DOM to compare the actual one.
Updating our components is an essential part of our applications. Showing our updated content to our users is essential, and we should always know what will be shown to the user after an interaction.
In React, we have something called the React component’s lifecycle, which is a collection of a React component’s stages, which we’ll look into
componentDidMount
This is the first stage of a React component’s lifecycle where the component is created and inserted into the DOM. In this lifecycle stage, we have the componentDidMount
lifecycle method, and executes when our component mounts:
componentDidMount() { console.log("The component has mounted successfully!"); this.setState({ loaded: true }) }
componentDidMount
allows us to use setState
so we can easily set and modify our state in the lifecycle method. This lifecycle method executes API calls, make calls to remote endpoints, and retrieves data.
In this stage, the render
method renders the component into the DOM and is the only method required.
shouldComponentUpdate
and componentDidUpdate
This updating stage happens after the component mounts and renders into the DOM. A React component then updates when we have an update in our props or state.
We have some lifecycle methods that we can use in this specific lifecycle, such as shouldComponentUpdate
and componentDidUpdate
.
The shouldComponentUpdate
lifecycle method is very easy; we simply return a boolean to determine if React should update the component. The default value for this method is true
:
shouldComponentUpdate() { return true; }
The shouldComponentUpdate
is called by React when the component is about to update/rerender. This method is what tells React whether the component will update or skip.
So, when React calls the shouldComponentUpdate
method on the to-be-updated component, React will check the shouldComponentUpdate
call result. If the result is true
, React will proceed to update the component. If the result is false
, React skips updating the component:
const instance = new HelloComponent() // HelloComponent is to be updated. // React will shouldComponentUpdate method. const isToRender = instance.shouldComponentUpdate() if(isToRender) { // if the 'isToRender' is true, then the HelloComponent is updated. instance.render() }
We also can simulate the shouldComponentUpdate
method in a functional component using React Hooks. Using useMemo
adds the shouldComponentUpdate
method to functional components:
function Parent({a, b}) { const HelloWorld = useMemo(() => <HelloComponent a={a} />, [a]) return {HelloWorld} }
Here, the useMemo
Hook takes in two arguments: a function and an array of dependencies, respectively.
The function argument is called when any of the dependencies in useMemo
changes. So, looking at our above code, the HelloComponent
only renders if a
changes from its previous value.
The componentDidUpdate
lifecycle method is invoked after the component updates. This lifecycle method compares if a specific prop or state changed:
componentDidUpdate(prevProps) { if (this.props.name !== prevProps.name) { console.log("Name has changed!"); } }
componentWillUnmount
This lifecycle is responsible for the cleanup in our DOM, especially when we want to remove a component from the DOM; in React, this is called unmounting.
We have just one lifecycle method for that lifecycle stage called componentWillUnmount
. This lifecycle method is invoked when a component is about to be removed from the DOM:
componentWillUnmount() { console.log("Component unmounted!"); }
A few lifecycle methods were deprecated in the React version 16.3.0:
componentWillMount
componentWillReceiveProps
componentWillUpdate
One of the main reasons that these lifecycle methods were deprecated is because when React implemented async rendering, the incorrect use of one of these lifecycle methods could lead to large errors, encourage unsafe coding practices, and in some situations, result in memory leaks.
If you’re still using one of these lifecycle methods in your actual application and planning to upgrade to the newest React version, you should know that in the React 17.0 version they were removed completely.
While you may have used one of these lifecycle methods in your applications before, and they’re really helpful and useful for a lot of situations, you might have noticed all these lifecycle methods are used in class components.
Check out this post that explains how these lifecycle methods work in class components. Now that we have React Hooks, we can deal and manage our state data in functional components, so how we can use lifecycle methods in functional components?
To manage our side effects in functional components, we have the useEffect
Hook, a Hook that can help us use lifecycle methods in functional components.
Let’s understand more about the useEffect
Hook and see how we can apply lifecycle methods in our functional components.
useEffect
to apply lifecycle methods in functional componentsIn class components, we have lifecycle methods to perform actions in a specific lifecycle stage of our component. For us to do something similar and perform side effects in our functional components, the React team created the useEffect
Hook.
To understand how the useEffect
Hook works, let’s first import it from React:
import { useEffect } from "react";
Now, in our component, we call the useEffect
Hook:
useEffect(() => { // Inside this callback function we perform our side effects. });
Here, it receives a callback function as the first parameter; this callback function will be our “effect.” The useEffect
Hook is called after every render of our component, that’s why we have a second argument.
As the second parameter, the useEffect
Hook receives an array of dependencies. But what does that mean?
Inside this array, we can pass the dependencies that the useEffect
Hook will watch. Bypassing an array of dependencies, the useEffect
Hook will only run if one of those dependencies changes.
So, imagine that we have a prop called username
; if we pass this prop as a dependency to the useEffect
Hook, it will only run if the username
prop changes:
useEffect(() => { // Pass an array of dependencies and the useEffect hook will only run if one of the dependencies changes. }, [name]);
If you pass an empty array to the useEffect
Hook, it will only run once after render. In the React documentation, the basic explanation of the useEffect
Hook is the following,
“If you’re familiar with React class lifecycle methods, you can think of useEffect
Hook as componentDidMount
, componentDidUpdate
, and componentWillUnmount
combined.”
Because of the useEffect
Hook, it’s very simple to perform side effects. In our case, we’ll perform the equivalent of some lifecycle methods.
componentDidMount
in functional components with useEffect
This is how we can perform the equivalent of componentDidMount
in functional components using the useEffect
Hook:
useEffect(() => { // Inside this callback function we perform our side effects. });
By simply calling the useEffect
Hook and passing the callback function, we preform the equivalent of the componentDidMount
lifecycle method. Very easy.
componentDidUpdate
with useEffect
To perform the equivalent of the componentDidUpdate
using the useEffect
Hook, we should do this:
useEffect(() => { // Inside this callback function we perform our side effects. }, [dependency]);
That’s it. It’s almost the same as the previous example, but this time we pass our dependency array as the second parameter, and inside that array, we pass the dependency that we want to watch.
If you don’t pass any dependency, the useEffect
Hook will still work as the componentDidUpdate
lifecycle method.
On the initial mount of the component, useEffect
runs the callback function without checking if the dependency
has changed or not.
Then, during the lifetime of the component when the state changes and the component updates, the dependencies array is checked to see if it changed since the recent update.
If any of the dependencies changed, the callback function will execute. If none of the dependencies changed, then the callback function does not executed:
useEffect(() => { // side-effects code here... }, [dependency1, dependency2, dependency3, ...., dependencyN])
If the useEffect
has no dependencies, then the callback function constantly executes whenever the component updates:
useEffect(() => { // side-effects code here... })
componentWillUnmount
with useEffect
To clean up after a component unmounts, we have a simple way to perform the equivalent of the componentWillUnmount
using the useEffect
Hook.
The only thing that we need to do is to return a function inside the callback function of the useEffect
Hook like this:
useEffect(() => { window.addEventListener("mousemove", () => {}); return () => { window.removeEventListener("mousemove", () => {}) } }, []);
That’s it. It’s very simple, and we can use the useEffect
Hook to perform side effects similar to the lifecycle methods that we have in class components with clean and straightforward code.
Now that we have React Hooks available, there’s no need to use class components anymore.
We can easily migrate all of our class components to functional components today, and if the lifecycle methods were the reason you have not migrated yet, now you can safely migrate to functional components and use React Hooks in your applications.
In this article, we learned more about a React component’s lifecycle and how it works. Then, we looked at the lifecycle methods in React, and how we can use the useEffect
Hook to use lifecycle methods in functional components.
Install LogRocket via npm or script tag. LogRocket.init()
must be called client-side, not
server-side
$ npm i --save logrocket // Code: import LogRocket from 'logrocket'; LogRocket.init('app/id');
// Add to your HTML: <script src="https://cdn.lr-ingest.com/LogRocket.min.js"></script> <script>window.LogRocket && window.LogRocket.init('app/id');</script>
Would you be interested in joining LogRocket's developer community?
Join LogRocket’s Content Advisory Board. You’ll help inform the type of content we create and get access to exclusive meetups, social accreditation, and swag.
Sign up nowBuild scalable admin dashboards with Filament and Laravel using Form Builder, Notifications, and Actions for clean, interactive panels.
Break down the parts of a URL and explore APIs for working with them in JavaScript, parsing them, building query strings, checking their validity, etc.
In this guide, explore lazy loading and error loading as two techniques for fetching data in React apps.
Deno is a popular JavaScript runtime, and it recently launched version 2.0 with several new features, bug fixes, and improvements […]
2 Replies to "Using React’s <code>useEffect</code> Hook with lifecycle methods"
Very well explained…Just one correction, for componentDidMount you need to pass an empty array as the second argument in the useEffect hook.
componentDidMount runs only initially, and we need to pass an empty array in the second argument to make our useEffect() hook work as componentDidMount 🙂