React Lifecycle Methods

The mounting phase

In the mounting phase, a component is prepared for and actually inserted into the DOM. To get through this phase, four lifecycle methods are called: constructor, static getDerivedStateFromProps, render, and componentDidMount.

constructor

The constructor method is the very first method called during the mounting phase.

It's important to remember that you shouldn't add any side effects within this method (like sending an HTTP request) as it's intended to be pure.

This method is mostly used for initializing the state of the component and binding event-handler methods within the component. The constructor method is not necessarily required. If you don't intend to make your component stateful (or if that state doesn’t need to be initialized) or bind any method, then it’s not necessary to implement.

The constructor method is called when the component is initiated, but before it’s rendered. It’s also called with props as an argument. It's important you call the super(props) function with the props argument passed onto it within the constructor before any other steps are taken.

This will then initiate the constructor of React.Component (the parent of this class-based component) and it inherits the constructor method and other methods of a typical React component.

For example, below you can see a class-based component implementation of a counter with a constructor in it, where the state is initialized and an event-handler method is bound (ignore the render method for now):

import React from 'react';

class Counter extends React.Component {
	constructor(props) {
		super(props);
		this.state = {
			count: 0
		};

		this.setCount = this.setCount.bind(this);
	}

	setCount() {
		this.setState({count: this.state.count + 1});
	}

	render() {
		return (
			<div>
				<h1>Counter</h1>
				<button onClick={this.setCount}>Click to add</button>
				<p>Count: {this.state.count}</p>
			</div>
		)
	}
}

In the Counter component, you can see the component's state is initialized within the constructor method to keep track of the count state. The setCount method, which is an event-handler attached to your button in this case, is bound within the constructor.

static getDerivedStateFromProps

Props and state are completely different concepts, and part of building your app intelligently is deciding which data goes where.

In many cases though, your component’s state will be derivative of its props. This is where the static getDerivedStateFromProps method comes in. This method allows you to modify the state value with any props value. It's most useful for changes in props over time, and we’ll learn later that it’s also useful in the update phase.

The method static getDerivedStateFromProps accepts two arguments: props and state, and returns an object, or null if no change is needed. These values are passed directly to the method, so there’s no need for it to have access to the instance of the class (or any other part of the class) and thus is considered a static method.

In the mounting phase, the getDerivedStateFromProps method is called after the constructor method and right before the component is rendered. This is the most rarely used method in this phase, but it’s still important to know so you can use it if needed.

For reference, here's an example of how getDerivedStateFromProps is used:

class UserPreview extends React.Component {
	
	constructor(props) {
		super(props);
		this.state = {
			...
			fullname: ""
		};
	}


	static getDerivedStateFromProps(props, state) {
		return {
			...
			fullname: `${props.firstname} ${props.lastname}`
		}
	}

	render() {
		// ...
	}
}

Another way of looking at it is just providing a default for your component state based on props.

render

The render method is the only required method for a class-based React component. It’s called after the getDerivedStateFromProps method and actually renders or inserts the HTML to the DOM.

Typically, the render method returns the JSX which will eventually be rendered, but it can also return other values.

It's important to remember that the render method is meant to be pure. This means you can’t modify the state, have any direct interaction with the browser, or any other kind of side effect like sending an HTTP request. Just think of it as writing HTML, but of course as JSX.

Below is an example of using the render method:


class SubmitButton extends React.Component {
	render() {
		return (
			<button
				type="submit"
				style={this.props.styles}
			>
				{this.props.child}
			</button>
		);
	}
}

componentDidMount

componentDidMount is the last lifecycle method called in the mounting phase. It’s called right after the component is rendered or mounted to the DOM.

With this method, you're allowed to add side effects like sending network requests or updating the component's state. Additionally, the componentDidMount method allows you to make subscriptions like subscribing to the Redux store. You can also call the this.setState method right away; however this will cause a re-render as it kicks in the update phase, since the state has changed.

You need to be careful with componentDidMount because it may cause unnecessary re-renders.

Here's an example using the componentDidMount method:


class NASACounter extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      count: 10
    };
  }

  componentDidMount() {
    const myTimer = setInterval(() => {
      this.state.count > 0
        ? this.setState({ count: this.state.count - 1 })
        : clearInterval(myTimer);
    }, 1000);
  }

  render() {
    return (
      <div style={this.props}>
        <h1>
          NASA Countdown: <br /> {this.state.count || "🪐"} <br />
          {"⭐".repeat(this.state.count) || "🚀"}
        </h1>
        {this.state.count === 0 && <h2>LIFT OFF!!!</h2>}
      </div>
    );
  }
}

A common use case is waiting until a component renders to start an animation, or fetching data from an external source.

The updating phase

The Updating phase is triggered when component props or state change, and consists of the following methods: static getDerivedFromProps, shouldComponentUpdate, render, getSnapshotBeforeUpdate, and componentDidUpdate.

The methods getDerivedFromProps and render are also part of the mounting phase. Since they’ve been covered previously, this section focuses on the other three methods.

static getDerivedStateFromProps

In the update phase, the first lifecycle method called is getDerivedStateFromProps. This method is useful if you have updated props and you want to reflect that in the component's state.

For instance, a component’s state may depend on the value of its props. With getDerivedStateFromProps, before the component was even re-rendered, its state can reflect those changes and can be shown (if applicable) to the newly updated component.

Remember, this method is rarely used and isn’t ideal for most situations.

shouldComponentUpdate

shouldComponentUpdate is another rarely used lifecycle method. It’s specifically intended for performance optimization, and basically lets you tell React when you don't need to re-render when a new state or props comes in. While it can help avoid re-renders, you shouldn’t rely on it to prevent re-renders since you might skip a necessary update and encounter bugs.

To prevent renders, you can opt in to logical rendering instead, or use a PureComponent which is recommended by React.

This method can accept nextProps and nextState as arguments, however, they’re optional, and you can declare it without the arguments. This method then returns a Boolean value. The Boolean value defines whether a re-render happens. The default value is true, where re-render happens in all cases whenever state or props changes.

Note that the shouldComponentUpdate method is ignored when forceUpdate() is invoked.

Here's an example using the shouldComponentUpdate lifecycle method:


class ShowWholeNumber extends React.Component {
	shouldComponentUpdate(nextProps, nextState) {
		return Math.round(nextProps.num) === Math.round(this.props.num);
	}

	render() {
		return (
			<div>
				The Whole number is: {Math.round(this.props.num)}
			</div>
		)
	}
}

getSnapshotBeforeUpdate

The getSnapshotBeforeUpdate method gives you access to the previous props and state of the component before it's updated. This allows you to work or check on the previous values of the state or props. It’s another method that’s rarely used.

A good use case for this method is handling scroll positions in a chat app. When a new message comes in as the user is viewing old messages, it shouldn’t push the old ones out of view.

getSnapshotBeforeUpdate is called after the render method, and before componentDidUpdate. If the getSnapshotBeforeUpdate method returns anything, it will be passed as a parameter for the componentDidUpdate method:


class ChatList extends React.Component {
  constructor(props) {
    super(props);
    this.chatsList = React.createRef();
  }

  getSnapshotBeforeUpdate(prevProps, prevState) {
    if (prevProps.list.length < this.props.list.length) {
      const list = this.chatsList.current;
      return list.scrollHeight - list.scrollTop;
    }
    return null;
  }

  componentDidUpdate(prevProps, prevState, snapshot) {
     if (snapshot !== null) {
      const list = this.chatsList.current;
      list.scrollTop = list.scrollHeight - snapshot;
    }
  }

  render() {
    return (
      <div ref={this.chatsList}>{/* ...contents... */}</div>
    );
  }
}

componentDidUpdate

The componentDidUpdate method is the last lifecycle method invoked in the update phase. It allows you to create side effects like sending network requests or calling the this.setState method. It’s important to remember that there should always be a way to avoid the setState (like some sort of logic), or it will result in an infinite loop of re-rendering.

This method can accept up to three parameters: prevProps, prevState, and snapshot (if you implement the getSnapshotBeforeUpdate method).

Here's an example of using componentDidUpdate method for implementing autosave functionality:


class WritePost extends React.Component {
	constructor(props) {
		super(props);
		this.state = {
			postContent: ""
		};

		this.handleInput = this.handleInput.bind(this);
		this.handleSubmit = this.handleSubmit.bind(this);
	}

	handleInput(e) {
		this.setState({postContent: this.state.postContent + e.target.value})
	}

	handleSubmit() {
		// ...
	}

	autosave() {
		// send network request to save post...
	}

	componentDidUpdate() {
		this.autosave()
	}

	render() {
		return(
			<form onSubmit={this.handleSubmit}>
				<input type={text} value={this.state.postContent} onChange={e => handleInput(e)} />
				<button type="submit">Post</button>
			</form>
		)
	}
}

The unmounting phase

The unmounting phase is the third and final phase of a React component. At this phase, the component is removed from the DOM. Unmounting only has one lifecycle method involved: componentWillUnmount.

componentWillUnmount

componentWillUnmount is invoked right before the component is unmounted or removed from the DOM. It’s meant for any necessary cleanup of the component, like unsubscribing to any subscriptions (i.e., Redux) or canceling any network requests. Once this method is done executing, the component will be destroyed.

Here's an example of using the componentWillUnmount to unsubscribe from a Redux store:


class MyComponent extends React.Component {
	constructor(props) {
		super(props);
		this.state = {
			...
		}

		// whatever bindings...
	}

	componentDidMount() {
		const { subscribe } = this.props.store;
		this.unsubscribe = subscribe(this.forceUpdate);
	}

	componentWillUnmount() {
		this.unsubscribe();
	}

	render() {
		return (
			<div>
				...
			</div>
		)
	}
}

Last updated