Dissecting the React Lifecycle and Related Methods

By |October 18th, 2016|Categories: es6, React|

React has proven to be wildly popular by Javascript developers, providing a foundation for building highly “reactive” components that are performant, efficient and generally scale well.

However, React can prove a little intimidating to get into, in part because the documentation can be cryptic, and in part because the toolset itself works largely by automating the normal messaging and event management that goes into developing web components. Understanding the React component lifecycle can go a long way towards figuring out what magic React is doing behind the scenes. This post will explore the major React lifecycle methods using a very simple “Loading…” component as a learning example.

A brief outline:

Initializating a Component

Covers getDefaultProps(), getInitialState() and render()

Initializing a component is performed by establishing both the defaults that are used in the template when a component is first defined and also identifying the state that the component should start with. It’s also customary to put the render() method in this step, as this makes it possible to actually see what the initial state looks like.

In the example covered here, the component in question is a “Loading …” span that emulates older text-based screens, where the word is followed by a growing string of periods or other characters until an upper bound is reached, at which point the “marching ants” (usually periods) start over. The example used here will showcase several stages of the React Life Cycle.

You can explore the code yourself below:

See the Pen Loading Demonstration by Kurt Cagle (@kurt_cagle) on CodePen.

When a new React Class is defined, the invoking structure passes in a JSX template (which looks something like an HTML or XML file) and an associated element that becomes the container for the DOM created by the template and the React libraries.

The base code for creating the component class then starting the rendering is show below:

The JSX template (here, ) creates the DOM for the component, with one attribute, maxCount holding the number of states that the Loading text can be in (from “Loading” to “Loading …”).

There are two methods within the React class definition that are responsible for setting up initial state conditions. The first, getDefaultProps(), returns property values from the template attributes or text content if these are not otherwise specified in the template definition.

It’s worth following the workflow here – the default parameters are passed as an object first, then the ReactDom.render() function looks at the template to adjust the parameters with the new values. In this case, the default maxCount parameter value is “5” but there is an attribute in the template called maxCount that then sets this to the value “4”. These in turn are passed into the class’s props collection (accessible by this.props in most event handlers, such as this.props.maxCount).

In addition to template properties, React components also have stored state via the this.state object. The getInitialState() method returns an object that is passed internally to the React environment. Normally, this is called internally on an empty object, but if this handler is defined, then the object that’s passed becomes the state properties for the component.

Here, the getInitialState returns an object with four fields – text (the “Loading” base string), count (the current number of characters to deploy), maxCount (same as this.prop.maxCount) and key (used for storing the setInterval() key used to clear the repeating loop).

Updating State and Properties

Covers componentWillReceiveProps()

React tracks changes to state automatically, but it does not react directly to changes in properties on the template in the same way. Instead, it is up to the user to handle code where the component itself gets modified.

Note below how maxCount propagates through from property to state variable. As expected, this is only called once, when the component is first initialized. Suppose, however, that an external process changed the attribute value. In that case, another function, componentWillReceiveProps() gets called with the updated properties, which can then modify the state, as follows:

The setState() method is very important when working with React. It may be tempting to just use a direct assignment (such as this.state.maxCount = nexProps.maxCount) but this, it turns out, doesn’t work. The reason for this is that React has to keep track of when a state variable gets changed, which means that internally it has to keep both the old and new values for that state until that comparison is completed. By using setState(), React can set a flag indicating that a particular state field has been changed, and then use that to help calculate whether it needs to re-render a component based upon that state change.

Note that there is no equivalent componentWillReceiveStates() function, as the bookkeeping for managing that function is performed by setState().

Once at this point, the component is ready to render. This is where the render() method is invoked. This shouldn’t change any internal state; rather, this renders the internal state using HTML or SVG content:

The render() function is called every time the component changes state, and returns templated output. In this case this outputs the text name followed by the supplied character (in this.props.char) by using the new ES6 repeat method for strings. Repeating the indicated number of characters.

It will write out “Loading”, then freeze. The variable this.state.count has a value of zero, so the character will be repeated zero times, as currently there’s no logic to update the variable.

Incorporating Time and Mounting

Covers componentWillMount(), componentHasMounted(), shouldComponentUpdate(), componentWillUpdate() and componentDidUpdate()

Once the object has been initialized, React then “mounts” the component into the HTML of the page. Remember that React’s render method must first check to insure that the state of the component has changed. If it has, then render is called to create a new image – what’s called a virtual DOM – that can be compared to the existing DOM. If the virtual and existing DOM are different, then the new DOM replaces the old.

Normally, React doesn’t do a lot of work with time-driven events, but this particular demo component requires the ability to update the component once every half a second. As a consequence, it becomes necessary to force a state update at a regular interval, which in turn will require a timer (or more properly, the setInterval() function).

The question is where to put it. In general, this should only be done once the component has been instantiated, so it can’t be placed with the existing initialization code. However, as a general rule of thumb nothing should be placed in the render() function that causes a state change in the component, which updating the count will automatically do.

As it turns out, React exposes two event handlers for precisely this situation. The first, componentWillMount is called just before the component is rendered to the screen for the first time, while componentDidMount is called immediately after the component code is rendered. The latter is perfect for starting the clock:

In the example, the componentDidMount() function handler sets the state of the key, while at the same time invoking the setInterval to fire a “tick” event every half second. Because the this keyword changes meaning depending upon where it’s called, a proxy reference to the class is persisted in ‘me’ and used to invoke the tick() handler that updates the count state value. This in turn initiates another re-render five hundred milliseconds later.

This block of code also sets up a second event ten seconds into the future that will call the finish() handler (specific to this component, not the overall lifecycle). When finish() is called the interval timer is cleared and the displayed text gets set to “Done”.

The mounting commands are only invoked once, when the component is first rendered. Three additional methods are exposed by the React object for handling subsequent updates: shouldComponentUpdate(), componentWillUpdate() and componentDidUpdate(). The shouldComponentUpdate() function returns true or false and determines whether the render() method needs to be invoked. Ordinarily, this will return true only if the state has been changed in some manner and false otherwise (as there’s no need to render if nothing has changed). However, if the component has external dependencies, then adding a new shouldComponentUpdate() that checks against those dependencies would allow the users to override the default behavior.

The componentWillUpdate() and componentDidUpdate() functions are invoked immediately before and immediately after the render as a way of either modifying state (without invoking a secondary re-render) or as a way of sending a notification that the component has changed its visual presentation. Additionally, if shouldComponentUpdate() returns false, then neither of these will be fired.

Thus, any state changes that are made will run through the chain of componentShouldUpdate() => componentWillUpdate() => render() => componentDidUpdate(). Additionally, these will fire during the initial mounting phase as well.

Cleaning Up

Covers componentWillUnmount()

The component actually works well enough at this point, but one of the things a good developer should do is to insure that there are no loose threads that may cause a call to be made after a page has refreshed to a new URL. This is where the final phase of a React component makes sense.

The final life cycle phase is componentWillUnmount(). This is called when the component itself is going out of scope, either by being overwritten or because a page change is about to occur. This becomes fairly useful in those settings where the component contains some state that needs to be persisted either to a local data store or to a server end-point, or by clearing timers. The latter would look something like this:

By setting this up, you are able to insure that an orphaned timer event won’t go off after a new page has been loaded into memory, generating an error.


With an understanding the React lifecycle, you should have a better idea about what’s happening in the background and to ensure that the code you’re writing is being performed at the proper time.

Kurt Cagle
Kurt Cagle (kurt.cagle@gmail.com) is an author of twenty books, blogger, and software architect, and is available for consulting or hire. He lives in Issaquah, WA with his wife, daughters, and cat.