A beginner's guide to the React component lifecycle

beginners-guide-react-component-lifecycle-header.png

A tutorial introducing the React component lifecycle. Aimed at React beginners and those who have not encountered the React component lifecycle before. The tutorial covers the various methods called throughout the lifecycle.

Introduction

In this tutorial, we will be learning the basics of React component lifecycle. When developing in React, every Component follows a cycle from when it’s created and mounted on the DOM to when it is unmounted and destroyed. This is what we refer to as the Component lifecycle. React provides hooks, methods that get called automatically at each point in the lifecycle, that give you good control of what happens at the point it is invoked. A good understanding of these hooks will give you the power to effectively control and manipulate what goes on in a component throughout its lifetime.

Our lifecycle is broadly categorized into three parts: Mounting, Updating and Unmounting. However, React 16 introduced a new method which, in this tutorial, we will allow to stand on its own. We will discuss each of these methods and how they can be used.

Requirements

To follow along, you will need to have knowledge of JavaScript, the ReactJS framework and a little over 5 minutes.

Mounting methods

A component mounts when it is created and first inserted into the DOM i.e when it is rendered for the first time. The methods that are available during this period are:

  • constructor()
  • componentWillMount()
  • render()
  • componentDidMount()

? The constructor and render methods are part of the basic concepts of React which this article assumes you are familiar with. We’ll proceed to discuss the other mounting methods.

The componentWillMount() Hook

⚠️ componentWillMount will be deprecated in React 16.3. However, React 16.3 is currently in Alpha (as of when this was written). You can use the constructor method or componentDidMount depending on what you need to be done. constructor will be called pre-render and componentDidMount post-render.

The componentWillMount method is called right before a component mounts or the render method is called. The truth is that you might hardly make use of this method in your React application. Let me explain why.

The componentWillMount method sits between the constructor method and the render method which puts it in a very odd position. Since it’s before the render method, it can be used to set the default configuration for a component, but this is mostly done using the constructor method. And since nothing changes between these two methods, there will be no need to set the configuration again.

Also, the render method has not been called at this point so nothing can be done with the DOM of the component since it has not been mounted. Some might think that this is the right place to make API calls for client-side rendering but this should not be done. API calls are asynchronous and the data might not be returned before the render method gets called. This means that the component might render with empty data at least once.

However, one good way to make use of this method is to perform any setup that can be done at runtime, for instance connecting to external APIs like Firebase. This setup should typically be done at the highest level of your component, like your root component, so the majority of your components will likely not make use of this method.

Here’s a simple example that you can try to see that this method actually gets called before the component is rendered:

1class Example extends React.Component {
2        componentWillMount() {
3            console.log('I am about to say hello');
4        }
5
6        render() {
7            return <h1>Hello world</h1>;
8        }
9    }

The componentDidMount() method

This method is available after the component has mounted. That is after the HTML from render has finished loading. It is called once in the component life cycle and it signals that the component and all its sub-components have rendered properly.

This is the best place to make API calls since, at this point, the component has been mounted and is available to the DOM. Generally, componentDidMount is a good place to do all the setup you couldn’t have done without the DOM. So here is a bunch of things you can do with this method:

  • Connect a React app to external applications, such as web APIs or JavaScript frameworks.
  • Set Timers using using setTimeout or setInterval.
  • Add event listeners.
  • Draw on an element you just rendered.

Practically, anything that should be setup in the DOM can be done here. So here’s an example of using the componentDidMount method to make API calls:

1class Example extends React.Component {
2        componentDidMount() {
3            fetch(url).then(results => {
4                // Do something with the results
5            })
6        }
7    }

Updating methods

Components do not always remain in the same state after mounting. Sometimes the underlying props could change and the component has to be re-rendered. The updating lifecycle methods give you control over when and how this updating should take place.

There are five updating lifecycle methods and they are called in the order they appear below:

  • componentWillReceiveProps
  • shouldComponentUpdate
  • componentWillUpdate
  • render
  • componentDidUpdate

We won’t discuss the render method as the article assumes you have knowledge of React already. Let’s discuss the others.

The componentWillReceiveProps() method

⚠️ This method is set to be deprecated in React 16.3. However, React 16.3 is currently in Alpha (as of when this was written). Read this article for more information and recommendations.

Props are externally passed into a component by its parent component. Sometimes these props are hooked to the state of the parent component. So if the state of the parent component changes, the props passed to the component changes and it has to be updated. If the props are tied to the state of the component, a change in it will mean a change in the state of the component.

componentWillReceiveProps is a method that is called before a component does anything with the new props. This method is called with the new props passed as an argument. Here, we have access to the next set of props and the present ones. Therefore, using this method, we can compare the present props with the new ones and check if anything has really changed.

⚠️ React may call this method even though nothing has really changed so make sure to make a comparison. If nothing has changed, there will be no need to change the state of the component. But if it has changed, then this change can be acted upon.

Here’s an example of the method in use:

1class Example extends React.Component {
2      constructor(props) {
3        super(props);
4        this.state = {number: this.props.number};
5      }
6
7      componentWillReceiveProps(nextProps) {
8        if (this.props.number !== nextProps.number) {
9          this.setState({number: nextProps.number});
10        }
11      }
12
13      render() {
14        return (
15          <h1>{this.state.number}</h1>
16        )
17      }
18    }

In the example above, this.state.number will only be updated if the new number is different from the previous one. So if there’s no difference then the state is not updated.

The shouldComponentUpdate() method

This method is called before the component re-renders after receiving a new set of props or there’s a new state. We can see that it receives two arguments, the next props, and the next state. The default behavior is for a component to re-render once there’s a change of state of props.

shouldComponentUpdate is used to let React know that a component’s output is not affected by a change of props or state in the component and thus should not re-render. It returns either a true or false value. If it returns true, the component will go ahead and do what it always does, re-render the component. If it returns false then the component will not update. Note that this does not prevent child components from re-rendering when their state changes.

The best way to use this method is to have it return false and hence the component will not update under certain conditions. If those conditions are met, then the component does not update.

In the example below, the component will only update if the new input is different from the previous:

1class Example extends React.Component {
2      [...]
3
4      shouldComponentUpdate(nextProps, nextState) {
5        if (this.state.input == nextState.input) {
6          return false;
7        }
8      }
9
10      [...]
11    }

⚠️ shouldComponentUpdate is a great place to improve the performance of a component because it can help to prevent unnecessary re-rendering. However, it is advised not to use this method for deep equality checks or JSON.stringify as this is very inefficient and may harm performance.

The componentWillUpdate() method

⚠️ This method is set to be deprecated in React 16.3. However, React 16.3 is currently in Alpha (as of when this was written). Read this tutorial for more information and recommendations.

componentWillUpdate is the method that can be used to perform preparation before re-rendering occurs. You cannot call this.setState in this method.

One major thing that can be done with this method is to interact with things outside of the React architecture. Also, if you need to do any non-React setup before a component renders such as interacting with an API or checking the window size, componentWillUpdate can be used.

Another time to use this method is if you are using shouldComponentUpdate and need to do something when the props change. In this scenario, it is preferable to use it instead of componentWillReceiveProps and it will be called only when the component will actually be re-rendered. However, if you need state to change in response to change in props, use componentWillReceiveProps instead.

While it can be used to perform animations and other effects, it should not be done as this method might be called multiple times before the component is actually re-rendered.

Here is the syntax:

1class Example extends React.Component {
2      [...]
3
4      componentWillUpdate(nextProps, nextState) {
5          // Do something here
6      }
7
8      [...]
9    }

The componentDidUpdate() method

componentDidUpdate is called after any rendered HTML has finished loading. It receives two arguments, the props and state of the component before the current updating period began.

componentDidUpdate is the best place to perform an interaction with a non-React environment like the browser or making HTTP requests. This should be done as long as you compare the current props to the previous props to avoid unnecessary network requests.

Here is an example of it in use:

1class Example extends React.Component {
2      [...]
3
4      componentDidUpdate(prevProps, prevState) {
5        if (this.props.input == prevProps.input) {
6          // make ajax calls
7          // Perform any other function
8        }
9      }
10
11      [...]
12    }

Unmounting method

Components do not always stay in the DOM. Sometimes they have to be removed due to changes in state or something else. The unmounting method will help us handle the unmounting of components. We say method because there is just one method as at React 16.

The componentWillUnmount() method

This is the only unmounting method. componentWillUnmount is called right before a component is removed from the DOM. This is where you can perform any cleanups that should be done such as invalidating timers, canceling network requests, removing event listeners or canceling any subscriptions made in componentDidMount.

1class Example extends React.Component {  
2      [...]
3
4      componentWillUnmount() {
5          document.removeEventListener("click", SomeFunction);
6      }
7
8      [...]
9    }

The componentDidCatch() method

? This lifecycle method was added in React 16 and is used in error boundaries.

A component becomes an error boundary if it defines the componentDidCatch method. In this method, this.setState can be called and used to catch an unhandled JavaScript error in a child component tree and display a fallback UI instead of the component that crashed. These errors are caught during rendering, in lifecycle methods, and in constructors of the whole tree below them.
This is to ensure that an error in a child component does not break the whole app.

It is important to note that this method only catches errors in child components and not in the component itself.

This method has two parameters. The first is the actual error thrown. The second parameter is an object with a componentStack property containing the component stack trace information. With these parameters, you can set the error info in state and return an appropriate message in its render method or log to a reporting system.

Here’s an example of how this method can be used in error boundaries:

1class ErrorBoundary extends React.Component {
2      constructor(props) {
3        super(props);
4        this.state = { hasError: false };
5      }
6
7      componentDidCatch(error, info) {
8        this.setState({hasError: true });
9      }
10
11      render() {
12        if (this.state.hasError) {
13          return <h1> Oops!!! Broken </h1>;
14        }
15
16        return this.props.children;
17      }
18    }

Conclusion

React is an extremely powerful JavaScript framework and understanding how the component lifecycle works will unlock new potential for power that you can explore.