What are React Component Lifecycle Methods

Read it in 9 Mins

Last updated on
09th Apr, 2021
Published
30th Mar, 2021
Views
9,342
What are React Component Lifecycle Methods

React is the most popular JavaScript library used to create interactive UI for web applications. It is a component-based library where different parts of a webpage can be encapsulated by components which are quite easy to create, manage and updateReact allows us to create Single Page Applications which maintain the state of individual components on an app without having to reload it.  

What are React Components? 

Developers who are new to JavaScript libraries and frameworks like React and Angular might ask the question, “What is a component? Well, in very simple words, a component is a unit of code which includes JavaScript and HTML to build a part of a web page. It acts like a custom HTML element. It is reusable and can be as complex as you want it to be. 

For example, imagine that you are creating a very basic application with header, footer, and body. The header can be a component; the footer can be another component and the body can be yet another one or even might consist of multiple components.

What are React Components

One of the most useful characteristics of React is its ability to integrate reusable components in a project. Reusability is the characteristic of component which allows it to be used again, thereby reducing the amount of code a developer has to write. In our example here, the header can be a reusable component and can be used on all the pages of the application, which makes it easy to maintain and update. 

What does a component look like? 

Here is a simple example of a react component which contains a simple form. This is a class-based component. React also supports function-based components. 

As you can see in the code below, App is a user-defined class which inherit from React’s Component class and it has a render method which returns HTML code. As the name suggests, the render method returns and renders HTML to our browser. Every component has to return HTML which is rendered to the user’s browser by render method.

importReact, { Component } from'react'; 
classAppextendsComponent { 
  handleChange(event) { 
    this.setState({value:event.target.value}); 
  } 
  render() { 
    return ( 
      <formonSubmit={this.handleSubmit}> 
        <label> 
          Username: 
          <inputtype="text"value={this.state.username}onChange={this.handleChange}/> 
        </label> 
        <label> 
          Password: 
          <inputtype="password"value={this.state.password}onChange={this.handleChange}/> 
        </label> 
        <inputtype="submit"value="Submit"/> 
      </form> 
    ); 
  } 
} 
 
exportdefaultApp; 

In the above example, we have created a login form where there are 2 input boxes for the user to enter their username and password and then submit the form. We have assigned an event handler to form which will handle the login event in component.

We have exported our component (using export default App) so that it can be rendered inside other components.

This is a very basic example of component, but this can be as complex as you want it to be. But it is always advised to make your component independent and it should represent only a part of your page which can be reusable as well. It can return complex HTML included with JavaScript to handle complex features in your application.

Component as a class 

React allows us to create component in the form of class as well as functions. While creating component as class you need to define a class which extends React.Component class. Component class has many features which the deriving class can use to maintain the state throughout the lifecycle. In case you want to have more custom features, you can create your own base component class which derives from Component class, and then your component classes can derive from your base component class. 

What do we mean by Component Lifecycle?

Lifecycle of a component is the set of different stages (also known as lifecycle hooks) a component goes through while it is active. Stages could be when a component is created or when any changes are made to the component and many others. There are different methods executed by React at different points of time between when a component is created and at the end when it is destroyed and not in use. 

One such hook or method we have already seen in the code above, which is render(), and it is executed by React to render the component. 

We can override these methods and perform certain tasks in those methods, but every lifecycle serves a different purpose and it can be a nightmare if we ask them to do something that they aren’t supposed to or are not very good at. 

As a developer we should be aware of what those different stages arewhat happens in those stages, in what order they execute and how we can make the best use of it. Understanding the lifecycle of components also helps us predict behavior of a component at different stages, which makes it easier to work with them. Managing a large set of components in an application can get you in trouble if you do not know how they work behind the scenes.

Props and State 

Before we start with lifecycle hooks, lets understand what props and state are as they are most commonly used properties in component classes. 

Props 

It is a keyword which means properties. Props are used by callers of components to pass properties to the called component in a uni-directional flow. For example, if Parent component renders child component, it can define props and pass them to the child component which is then available and accessible by this.props. 

Another thing to note here is that props is a ready-only attribute which means data which is passed by parent should not be changed by client components. 

State 

State is a plan JavaScript object which defines the current state of any component. It is user defined and can be changed by lifecycle hooks. Ideally state should contain only data which is going to be rendered on DOM. 

State has getter and setter methods this.getState() and this.setState() which as the names suggest are used to access and update State. It is good practice to use setState method to update State and treat State as an immutable JavaScript object.

Since there are many lifecycle hooks a component goes through, it would easier to understand if we start with the hooks which are executed when a component is created.

Lifecycle hooks while Mounting 

[These lifecycle hooks are executed in order as listed, when component is created]

constructor(props) 

This is not a component lifecycle hook, but it is important to mention here and to be aware that Constructor is executed before it is mounted. Constructor receives props(properties of a component) as an argument which then can be passed to base class using super keyword if we define the constructor.  

It is not mandatory to define constructor in component class, but if you do to perform any logic, then you need to call base constructor using super keyword.  

Mainly constructors are used: 

  1. To Setup local state of component with this.state 
  2. To bind event handler methods. 

This is what a simple constructor would look like.

importReact, { Component } from'react'; 
classAppextendsComponent { 
  constructor(props) { 
    super(props); 
    this.state = { value:0 }; 
    this.handleClick = this.handleClick.bind(this); 
  } 
} 

this.state should be called only inside constructor, to update the state in other methods use this.setState() method.  

If constructor is required to do any heavy tasks, it will impact the performance of component, and you should be aware of this fact.  

getDerivedStateFromProps(props, state) 

After constructor, this lifecycle hook is called before render method is executed. It is called while mounting as well as whenever props have changed. This is not very commonly used, only in cases where props can change, and you need to update state of the component. This is the only use case where you should implement this lifecycle hook.

This method is executed on every render and cannot access component instance.

importReact, { Component } from'react'; 
classAppextendsComponent { 
  getDerivedStateFromProps(props, state) { 
    if (props.value !== state.prevValue) { 
      return { 
        prevValue:props.value 
      }; 
    } 
    returnnull; 
  } 
 
}

render() 

This is the method which is required to be implemented in component class. It can access props and state. 

This is where you can write your html and jsx code. You can also render child components in this method which will then be rendered as well. Before completing the lifecycle of parent, lifecycle of all child components will be finished. All this html and jsx is then converted to pure html and outputs in DOM. 

JSX is JavaScript extension which creates React elements. It looks more like template language but it is empowered by JavaScript which allows it to do a lot more. It can embed expressions <img src={value}  />. JSX has different set of attributes than what we have in html. For example, while creating html using JSX you need to use attribute “className” instead of class. 

This is what a typical render method looks like:

import React, { Component } from 'react';   
class App extends Component { 
  render() { 
        return ( <div> 
      <h1 > Click to go Home { this.state.home }</h1> 
      <button type="button" onClick = { this.redirectToHome } >Go to Home     </button> 
    </div>); 
  } 
} 

Alternatively you can also use React.createElement() method to create html using JSX.

const element = React.createElement( 
      'h1', 
      {className: 'hello'}, 
      'Hello, world!' 
    );

componentDidMount() 

As the name suggests, componentDidMount() is invoked after the component is mounted, which means html has been added to DOM tree. 

It is very commonly used lifecycle hook, as it allows you to do lot of things including causing side-effects, setting up any subscriptions, or loading data from external endpoints. If you setup any subscription using this method, make sure to unsubscribe them in componentWillUnmount() lifecycle hook. 

You shouldn’t update state in this method using this.State() as it may cause performance issues. For assigning initial state you should use constructor(). 

importReact, { Component } from'react'; 
classAppextendsComponent { 
  componentDidMount(){ 
  // Component is rendered and now external calls can be made. 
    this.getDataAfterTimeOut(); 
  } 
  getDataAfterTimeOut(){ 
    setTimeout(() => { 
      this.setState({ 
        data:'Data is fetched' 
      }) 
    }, 1000) 
  } 
} 

Lifecycle hooks while Updating 

[Next set of lifecycle hooks are executed while a component is updating which can be caused by changes to props(properties) or state of component. These are invoked in order as listed below.] 

getDerivedStateFromProps(props, state) 

We have already talked about this. This is invoked every time a component is changed or updated. Any changes in properties or state which causes the component to be changed will invoke this method. 

shouldComponentUpdate(nextProps, nextState) 

shouldComponentUpdate() is invoked before rendering (not on initial rendering) but only when props or state has been changed. Even though it is not recommended you can use this lifecycle hook to control the re-rendering. This can lead to performance issues as well as bugs, so be careful while doing that.  

In this method nextProps can be compared with this.props and nextState can be compared with this.state. 

This method can return true or false depending on whether you want to continue rendering by skipping the next lifecycle hooks. In either case it can’t prevent re-rendering of child components. 

Note that this method defaults to true which will not skip rendering and next lifecycle hooks and continue with execution. 

importReact, { Component } from'react'; 
classAppextendsComponent { 
  shouldComponentUpdate(nextProps, nextState) { 
// This value will determine if lifecycle execution is to be skipped or continued. 
    returnnextProps.value != this.props.value; 
  } 
} 

render() 

After shouldComponentUpdate lifecycle hook render is called, which we have already talked about, it prepares html and jsx code which then outputs to DOM. 

getSnapshotBeforeUpdate() 

getSnapshotBeforeUpdate() is invoked right before the recent changes are added to DOM. This lifecycle hook gives us an opportunity to capture any details we need from the DOM before it is updated with new content. For example, if you want to know the scrolling position of the user, which should be restored after the DOM has changed. Use cases for this lifecycle, while rare, can be of great value at times. 

The snapshot value which is captured and returned by this hook is passed as parameter to another lifecycle hook componentDidUpdate() which we will talk about next. 

importReact, { Component } from'react'; 
classAppextendsComponent { 
  getSnapshotBeforeUpdate (prevProps, prevState) { 
// implementing this method here allows us to capture the snapshot of current dom tree. 
    if (this.state.value != prevState.value) { 
      returntable.scrollHeight - table.scrollTop 
    } 
    returnnull 
  } 
}

componentDIdUpdate(prevProps, prevState, snapshot) 

componentDidUpdate is invoked when DOM is updated. It is only called on update, not on initial rendering. You can use this method to make data requests after checking if props have changed. 

You can also call setSatate() in this method, but make sure to wrap that in a condition else it will cause an infinite loop forcing re-rendering and affecting performance issues. 

Also it should be noted that value for snapshot will only be available if you have implemented getSnapshotBeforeUpdate() in your componentelse value for snapshot will be undefined. 

Here is an example of componentDidUpdate. This is a very basic example where we have captured snapshot by implementing get Snapshot Before Update lifecycle hook. 

After that componentDidUpdate is invoked and content is overwritten with new data

importReact, { Component } from'react'; 
classAppextendsComponent { 
  getSnapshotBeforeUpdate(prevProps, prevState) { 
// implementing this method here allows us to capture the snapshot of current dom tree. 
    document.getElementById("divContent").innerHTML = 
    "Before the update content is " + prevState.content; 
  } 
  componentDidUpdate(prevProps, prevState, snapshot) { 
// You can access snapshot here to get data from dom before it was updated. 
    document.getElementById("divContent").innerHTML = 
    "New content updated " + this.state.content; 
  } 
} 
importReact, { Component } from'react'; 
classAppextendsComponent { 
  getSnapshotBeforeUpdate(prevProps, prevState) { 
// implementing this method here allows us to capture the snapshot of current dom tree. 
    document.getElementById("divContent").innerHTML = 
    "Before the update content is " + prevState.content; 
  } 
  componentDidUpdate(prevProps, prevState, snapshot) { 
// You can access snapshot here to get data from dom before it was updated. 
    document.getElementById("divContent").innerHTML = 
    "New content updated " + this.state.content; 
  } 
} 

UnMounting 

[This is where lifecycle of a component ends when component is destroyed and removed from DOM. While Unmounting React gives us an opportunity to do something before component is destroyed, it can include clearing objects which have occupied memory to avoid memory leaks.] 

componentWillUnMount() 

componentWIllUnMount() is executed right after component is unmounted which means it is removed from DOM and destroyed. But before it is removed and destroyedReact gives us an opportunity to perform any cleanup we want to. For example, you might have setup subscriptions initially in componentDidMount() which you should unsubscribe when component is destroyed to avoid memory leaks in your application. You can also remove event listeners which were subscribed before. 

In this lifecycle hooks you should not update state of your component because component is not going to re-render now.

importReact, { Component } from'react'; 
classAppextendsComponent { 
  componentWillUnmount() { 
// Component will be removed from DOM now.  
     // Unscubscribe subscriptions and events here. 
document.removeEventListener("click", this.handleSubmit); 
  } 
}

Conclusion 

In this article we talked about React, its components and its different lifecycles. It is very crucial to understand the different opportunities that React provides through these lifecycle methods. There are many rules we need to follow while working with these hooks. Making them do something they can’t handle can cause performance issues or even infinite loops at times.  

These lifecycle hooks work with props and state which are the most used properties of component class. Changes in state and props trigger different lifecycle hooks and even re-render the dom which is something you should be aware of. These lifecycle hooks are provided to intercept the different stages a component goes through and make the best use of it, but without understanding how they work it can break your application by causing performance issues or memory leaks. 

Hope this has been helpful. 

Profile

Dheeraj Kumar

Author

Dheeraj is a Full Stack Developer, Trainer and Architect. He has more than 8 years of experience with .NET and JavaScript stacks building enterprise applications. He has trained more than 1000 students and professionals in .Net, MEAN and MERN stack.