Leonardo Maldonado Fullstack developer. JavaScript, React, TypeScript, GraphQL.

Using React’s useEffect Hook with lifecycle methods

6 min read 1694

Using React useEffect Hook Lifecycle Methods

Editor’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:

Component lifecycle and lifecycle methods

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

Mounting phase with 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.

Updating phase with 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!");
  }
}

Unmounting phase with 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!");
}

Deprecated React lifecycle methods

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.

Using useEffect to apply lifecycle methods in functional components

In 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.


More great articles from LogRocket:


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.

Using 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.

Using the 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...
})

Using 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.

Conclusion

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.

Cut through the noise of traditional React error reporting with LogRocket

LogRocket is a React analytics solution that shields you from the hundreds of false-positive errors alerts to just a few truly important items. LogRocket tells you the most impactful bugs and UX issues actually impacting users in your React applications. LogRocket automatically aggregates client side errors, React error boundaries, Redux state, slow component load times, JS exceptions, frontend performance metrics, and user interactions. Then LogRocket uses machine learning to notify you of the most impactful problems affecting the most users and provides the context you need to fix it.

Focus on the React bugs that matter — .

Leonardo Maldonado Fullstack developer. JavaScript, React, TypeScript, GraphQL.

2 Replies to “Using React’s useEffect Hook with lifecycle methods”

  1. Very well explained…Just one correction, for componentDidMount you need to pass an empty array as the second argument in the useEffect hook.

Leave a Reply