Life cycle methods in react explained as a kid’s dance performance

Saurabh Mhatre
CodeClassifiers
Published in
7 min readMar 13, 2017
Image source:Pixabay

Reactjs has become quite popular as a frontend ui library in recent times.Similar to pages in traditional websites we split our entire react app into components and lifecycle methods are core drivers which run the components.

In today’s tutorial I am trying to explain this lifecycle methods for better understanding of core ecosystem of reactjs by taking an analogy of a kid preparing for a dance performance.

Imagine that reactjs is a kid who has to perform his dance performance in front of live audience and this methods are people/events which help him in delivering the performance.He also has two friends called state and props variables where state variables can be viewed as class level variables while props are parameters which can passed parent class to child class. React can give commands to state variables and update its value using setState method while it can only read the values of props using this.props argument.

So let’s go down the rabbit hole…

When we use the word first mounting we are referring to event when page is first displayed to the user.All the methods which are called before mounting are used to do all operations which need to be done before your page in rendered for the first time on the browser and there are others which are called after first render.You can see this methods as the preparation which needs to be done by reactjs before the dance performance.

  • constructor():

Constructor method is the first method which is called before mounting the component.It is similar to mother of our kid who takes care of all his needs before performance like the clothes,props and makeup.So first we need to thank her by calling the super(props) method without which this.props will be undefined in the constructor.

Next we can initialize all the required state variables.This is where we need to assign initial values which can then be used or modified further.

constructor(props) {
super(props);
this.state = {
songname:"My favourite song",
dancemoves:["step1","step2"],
speakervolume:0
};
}

For example in performing dance our kid will require the songname to dance on and steps which he needs to perform.

  • defaultProps

It can be defined as a property on the component class itself, to set the default values of props for the class.

import React from 'react';export default class Kid extends React.Component {
render() {
return (
<div>dressColor: { this.props.dressColor })</div>
);
}
}
Kid.defaultProps = { dressColor: 'red' };

If for some reason our kid fails to get his own dress for the performance then he can wear the default red colored dress provided by his school. If the parent Component fails to send dressColor prop to Kid class then it’s value will be set to red.

  • componentWillMount()

componentWillMount method is called immediately before mounting occurs.You can view this method as a scenario where our kid is standing behind the stage, doing all last-minute preparations and patiently waiting for curtains to be raised. Since it is called before first rendering of the page occurs, setting state in this method will not cause a rerender of page.

componentWillMount(){
this.setState({
speakervolume:5
})
}
  • componentDidMount()

It is called immediately after a component is mounted or page is shown to user and first render call is complete.You can view this method as a scenario where the curtain is just raised,our kid is just seen by the audience and the song is about to start.Our kid now needs to get over his nervousness, try to remember his first steps of the dance and start the performance.

Similarly if we need to get data from backend using direct ajax calls to server or invoke redux actions we can do it here.When we invoke setState in this method it will cause rerender of the page.

componentDidMount(){
axios.get('someurl/getfurthersteps')
.then((response) => {
console.log(response);
this.setState({dancesteps:response})
})
.catch((error) => {
console.log(error);
});
}

Now our kid had trouble remembering further steps so he looked at his teacher standing at the corner of the stage who prompted further steps to him.

In this case teacher is a server and our kid is a client which sent get request to server and stored response from server in dancesteps variable. Here I have used axios npm module to send get request to server.

  • componentWillReceiveProps()

It is invoked before a mounted component receives new props.What this essentially means is if we pass some props from parent class to child class after mounting then this method can be used to update the state of component based on the props received.This is possible when we pass state variable from one component as prop to its child class.

Imagine a scenario where our kid is now performing nicely on stage and receives applause from the judges then the kid will become happy rather than being nervous.

import React from 'react';
import Kid from './Kid';
export default class Judge extends React.Component {
constructor(props) {
super(props);
this.state = { applause: false } ;
this.handleChange = this.handleChange.bind(this);
}
handleChange(event) {
this.setState({ applause: true });
}
render() {
return (
<div>
<button type="button" onChange={()=> this.handleChange() }>
Appreciate performance
</button>
<Kid applause={ this.state.applause } />
</div>
);
}
}

Here the Judge class is passing applause to Kid class as prop whose state in updated by handleChange function on button click.

import React from 'react';export default class Kid extends React.Component {
constructor(props) {
super(props);
this.state = { emotion: 'nervous' } ;
}
componentWillReceiveProps(nextProps) {
if(nextProps.applause){
this.setState({ emotion: "happy" });
}
}
render() {
return (
<div>
Our kid is currently {this.state.emotion}
</div>
);
}
}

In componentWillReceiveProps we check the value of applause prop and if it is true then we set emotion state of kid to happy.

  • shouldComponentUpdate()

It is invoked before rendering when new props or state are being received. We can use this method for performance optimizations and to prevent unnecessary render calls.It is generally not feasible to use shouldComponentUpdate unless your render method takes up a lot of time in processing. Instead of trying to optimize your render cycles yourselves, first check you render cycle time in profiler and if you are sure that some component is slowing your app then use React.PureComponent which implements the method with shallow prop and state comparision.

import React from 'react';export default class Judge extends React.Component {
constructor(props) {
super(props);
this.state = { stepcount: 1,
danceMarks: 0 } ;
}
incrementStepCount(event){
this.setState({
stepcount: this.state.stepcount + 1
});
}
dancemarksCount(event){
this.setState({
dancemarks: this.state.dancemarks + 1,
});
}
shouldComponentUpdate: function(nextProps, nextState) {
if(nextState.stepcount !== this.state.stepcount)
return true;
else if(this.state.dancemarks >= 5)
return true;
else
return false;
},
render() {
return (
<div>
<div>Count: {this.state.stepcount}</div>
<div>finaldanceMarks: {this.state.dancemarks}</div>
<div><button onClick={(event) => this.incrementStepCount(event)}>Increment stepCount</button></div>
<div><button onClick={(event) => this.dancemarksCount(event)}>Increment marks</button></div>
</div>
);
}
}

Suppose the judge who is examining the student performance keeps a track of steps done properly by the kid and increments marks accordingly.Now he can show stepcount to kid but does not want to show his marks until they are greater than 5 so on every stepcount increment we return true from this method to allow rerendering of component but we prevent rerender cycle until dancemarks are incremented to 5 until which we are returning false in shouldComponentUpdate.

The implementation of this method must be strictly avoided until and unless absolutely required since incorrect implementation can lead to various bugs in the code.

  • componentWillUpdate()

It is invoked immediately before rendering when new props or state are being received.We can use this method to compare old props/state variables to newer ones and invoke some function based on those values.It is called every time a re-render is required, such as when setState is called.

We should never call setState method here since it will trigger another componentWillUpdate and we will end up in an infinite loop.

componentWillUpdate(nextProps, nextState) {
if (nextState.marks == 10 && this.state.marks == 9) {
this.props.Qualified();
}
}

The moment our Kid’s mark are changed to 10 from 9 we can call Qualified function which might be it’s parent class to let the kid know that he is qualified.

  • componentDidUpdate()

It is invoked immediately after dom updating occurs. This method is not called for the initial render.We can use this as an opportunity to operate on the DOM when the component has been updated.The most common use case of this method is we use 3rd party libraries like d3.js or charts library like c3.js and we need to update UI library with new data.One of the notable difference between componentDidUpdate and componentWillUpdate is that didUpdate gets old props/state variables as input while willUpdate gets new props/state variables as input.

componentDidUpdate(prevProps, prevState) {
// only update chart if the data has changed
if (prevProps.marksdata !== this.props.marksdata) {
this.chart = c3.load({
marksdata: this.props.marksdata
});
}
}

If we are displaying marks recieved by kid over time of his performance as a chart then we can trigger change in charts only if marks are changed post render cycle.

  • componentWillUnmount()

It is invoked immediately before a component is unmounted and destroyed. Perform any necessary cleanup in this method, such as invalidating timers, canceling network requests, cleaning up any DOM elements that were created in componentDidUpdate/componentWillMount or destroy 3rd party UI library elements.If we don’t take the time to remove events we can create memory leaks in our system or leave bad references lying around.

import React from "react";export default class Kid extends React.Component {  resizeDiv = this.handleResize.bind(this);  constructor()
{
super();
this.state = {height:window.innerHeight + "px"};
}
handleResize(e)
{
this.setState({height:window.innerHeight + "px"});
}
componentDidMount()
{
window.addEventListener('resize', this.resizeDiv);
}
componentWillUnmount()
{
window.removeEventListener('resize', this.resizeDiv);
}
render() { return (
<div class="lead_div" style={{height:this.state.height}}>
Dancing div
</div>
);
}
}

We added a listener to our div to change its height based on change in window height in didMount method. We removed this listener in willUnmount method.

Phew…That finally covers all the lifecycle methods called in various phases of mounting.

Here is a complete breakdown of all methods for reference in the future:

Methods called during mounting:

  1. Component.defaultProps
  2. this.state/constructor
  3. componentWillMount
  4. render
  5. componentDidMount

Methods called for updating Component:

  1. componentWillRecieveProps
  2. shouldComponentUpdate
  3. componentWillUpdate
  4. render
  5. componentDidUpdate

Methods called during unmounting:

  1. componentWillUnmount

If you need even more in-depth explanation about lifecycle methods then head over to react indepth git book here.

Connect Deeper

In the next article I am planning to cover creation of admin dashboard in reactjs so follow us on facebook here

--

--