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.
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.
To follow along, you will need to have knowledge of JavaScript, the ReactJS framework and a little over 5 minutes.
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.
⚠️
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 theconstructor
method orcomponentDidMount
depending on what you need to be done.constructor
will be called pre-render andcomponentDidMount
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 }
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:
setTimeout
or setInterval
.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 }
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.
⚠️ 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.
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 orJSON.stringify
as this is very inefficient and may harm performance.
⚠️ 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 }
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 }
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.
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 }
? 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 }
React is an extremely powerful JavaScript framework and understanding how the component lifecycle works will unlock new potential for power that you can explore.