The React Lifecycle, step by step

Vinicius Marchesin Araujo
6 min readSep 3, 2018

It’s been quite a while since React came out, and since then many changes were introduced. Some of those impact the React Component Lifecycle, so I figured it would be good for both veterans and newcomers to the framework to get a glimpse of how the most recent lifecycle methods works. If you already know what each method does, I hope this gives a better overview of the process.

This article is based on the most recent version of React, which is v16.4.2. If you are reading this in the future make sure to read the docs and check for new or deprecated features.

React Lifecycle Diagram https://tinyurl.com/react-lifecycle

The lifecycle has three main sections:

  • Mounting: Runs once when the component is created.
  • Updating: Runs each time a change is made to the component.
  • Unmounting: Runs once when the component is about to be destroyed.

There are also three phases, which run multiple times during the lifecycle:

  • Render phase: Is used to calculate changes, and may be aborted if the user wants to. If this phase is aborted the DOM isn’t updated.
  • Pre-commit phase: Is a period where you can read changes made to the VDOM, before they are applied to the actual DOM. To learn more about the VDOM I recommend this article.
  • Commit phase: Here the changes are applied and any side effects are triggered.

Since this article is focused on the lifecycle, I think it’s easier to focus on the time aspect, instead of the methods themselves. This approach provides a better sense of progress and makes it easier to understand how each method interacts on each part of the cycle and at which point in time they are invoked. Also, to learn about how to use the methods just refer to the docs.

Mounting

constructor(props)

The first method called during mount is the constructor . If you’re familiar with OOP this should be self explanatory. This should be used to initialize the local state, or any other variables, and bind methods. If you don’t need to do neither of those then you don’t need a constructor.

If you invoke the constructor

constructor(props) {
super(props);
this.state = { counter: 0 };
// this.handleClick = this.handleClick.bind(this);
}
handleClick = () => { /* do something */ }

Quick tip: If you use the ES6 Arrow Function syntax on your methods you don’t need to bind the scope on your constructor. Use it when you don’t need the function’s own this , making your code cleaner.

getDerivedStateFromProps(props, state)

The next method is a recent introduction, created to replace componentWillReceiveProps . This is intended to update the state before rendering, and it should be used with caution. Since this is a static method it doesn’t have access to the component instance. In order to update the state just return a plain object, or null to update nothing. This serves the same purpose as setState() , but it runs earlier in the lifecycle.

static getDerivedStateFromProps(props, state) {
return { offsetX: props.offsetX * 2 }
}

render()

This is the only required method in a React Component. It is called for the first time during mount, and it’s used to render DOM nodes. This method should be pure, meaning that it shouldn’t modify the component state.

componentDidMount()

The last method called during the mounting phase, this is usually used to trigger side effects. Fetching asynchronous data, handling subscriptions or binding event handlers should be done here. You can also callsetState() at this point, and it will trigger an extra rendering before the browser updates the screen. This guarantees that the user won’t see the intermediate state.

Updating

The update lifecycle is the trickiest since it has multiple paths. After the initial mount, anytime and update is triggered this cycle will be called. Let’s start on how to trigger an update:

  • New props: Anytime a prop is changed or a new prop is introduced it will trigger an update.
  • setState(): Any change in the component state will trigger an update. Always use setState() , since changing the stateobject directly won’t trigger the lifecycle.
  • forceUpdate(): You can also force the component to update without any previous change.

Now for the methods, in the order they are invoked:

getDerivedStateFromProps(props, state)

This is the same method called during mount. It is triggered by a change on the statevia setState() or by receiving new propson your component. The principle is the same, use the props to update your stateby returning a new object, or null to skip the update.

shouldComponentUpdate(nextProps, nextState)

This method is used to intercept the update lifecycle. Here you can compare your current props and state to the next ones, and decide if you need to rerender or not. Up until this point the component’s propsand statedidn’t update yet, meaning you can access the old props using this.props and the old state using this.state , and compare them to the new ones received as arguments.

This method only exists as a performance optimization.

If you return false on this component the update ends here, and the render is prevented. If you return true or don’t declare this method the update continues.

If you use forceUpdate() this method is ignored and the render is called.

render()

Similar to the mounting phase, this will update the component and render it again based on your propsand statevalues. At this point using this.props or this.state will reflect the recent updates on your component.

getSnapshotBeforeUpdate(prevProps, prevState)

This is a new introduction on v16 as well. Since this runs after the render it can read the most recent DOM changes, right before they are actually applied. This is useful when you need to keep track of any changes made to the DOM before they are applied, for example keeping the scroll position if you have a dynamic feed.

Here you should return the observed values, as any return value will passed as the third argument to componentDidUpdate .

componentDidUpdate(prevProps, prevState, snapshot)

This serves the same purpose as componentDidMount , but it runs every time an update occurs. At this point the changes to the DOM were already committed, so you use it to manipulate the DOM, fetch asynchronous data and more.

You can also change the state using setState() here, but you must wrap it in a condition. Since any changes to the state triggers a new update, if you don’t do any verification it will cause an infinite loop.

After this method the update is finished.

Unmounting

componentWillUnmount()

This method is called when the component is about to be destroyed. Use this to clear timeouts, stop network requests and overall clean any leftover data. After the component is unmounted it can never be mounted again.

Deprecated Lifecycle Methods

These methods were introduced in previous versions of React and should be avoided. If you already have code using React consider removing these methods or renaming them to their UNSAFE_ counterparts (the previous names will be removed in v17), and if you intend to start a new project just don’t use them at all.

UNSAFE_componentWillMount()

This is invoked right before the mount takes place. Just move your logic to componentDidMount or the constructor if you need to initialize anything.

UNSAFE_componentWillReceiveProps()

This is invoked before a mounted component receives new props. Either perform side effects on componentDidUpdate or getDerivedStateFromProps to update the state . For more information on how to use derived state, refer to this blog post.

UNSAFE_componentWillUpdate(nextProps, nextState)

This is called between the render and componentDidUpdate . Usually you can move the logic from this method to componentDidUpdate , or if you read from the DOM move the logic to getSnapshotBeforeUpdate .

--

--

Vinicius Marchesin Araujo

Front-end developer and dolphin impersonator. Currently working as a JavaScript Developer at @Socialbakers in Prague. | https://vmarches.in