React Component Lifecycle

1 Lifecycle
A React component in browser can be any of the following three statuses: mounted, update and unmounted.

So React component lifecycle can be divided into three phases according to these statuses: mounting, updating and unmounting.


2 Mounting

2.1 Initializing state
2.2 Default props
2.3 componentWillMount()
2.4 componentDidMount()
React.js exposed interfaces or hook methods in each phase of component lifecycle.

2.1 Initializing state

You can optionally set initial state value in constructor() method of the component if you are using ES6 syntax.

const tom_and_jerry = [
    {
        name: 'Tom', 
        score: 55
    },
    {
        name: 'Jerry', 
        score: 80
    }
];

class ScoreBoard extends React.Component {
    constructor(props) {
        super(props);
        this.state = { players: tom_and_jerry }
    }

    // ...
}

If you are using ES5 syntax, getInitialState() in the right place to initialize component state.

var ScoreBoard = React.createClass({
    getInitialState: function() {
        return {
            players: tom_and_jerry
        }
    },

    // ...
});

The getInitialState() method is called only one time before the component is mounted.

Initialization of state should typically only be done in a top level component, which acts as a role of controller view in your page.

2.2 Default props

You can also define default values of component props (properties) if the parent component does not declare their values.

Return default props using ES7+ static property initializer.

class SinglePlayer extends React.Component {
    static defaultProps = {
        name: 'Nobody',
        score: 0
    }

    // ...
}

Default props in ES6:

class SinglePlayer extends React.Component {    
    // ...
}

SinglePlayer.defaultProps = {
    name: 'Nobody', 
    score: 0
}

You can define getDefaultProps() method in ES5.

var SinglePlayer = React.createClass({
    getDefaultProps: function() {
        return {
            name: 'Nobody', 
            score: 0
        }
    }
});

The getDefaultProps() method is called only once before any instance of the component is created. So you should avoid using this.props inside getDefaultProps() method.

2.3 componentWillMount()

The componentWillMount() method is invoked only once before initial rendering.

It is also a good place to set initial state value inside componentWillMount().

class SinglePlayer extends React.Component {
    componentWillMount() {
        this.setState({
            isPassed: this.props.score >= 60
        });

        alert('componentWillMount => ' + this.props.name);
        console.log('componentWillMount => ' + this.props.name);   
    }

    // ...
}

2.4 componentDidMount()

This lifecycle method will be invoked after rendering.

It is the right place to access DOM of the component.

class ScoreBoard extends React.Component {
    constructor(props) {
        super(props);
        this._handleScroll = this.handleScroll.bind(this);
    }
    handleScroll() {}
    componentDidMount() {
        alert('componentDidMount in NoticeBoard');
        window.addEventListener('scroll', this._handleScroll);
    }

    // ...
}

3 Updating

3.1 componentWillReceiveProps()
3.2 shouldComponentUpdate()
3.3 componentWillUpdate()
3.4 componentDidUpdate()

3.1 componentWillReceiveProps()

void componentWillReceiveProps(object nextProps)

This method will be invoked when a component is receiving new props. componentWillReceiveProps() won’t be called for the initial rendering.

class SinglePlayer extends React.Component {
    componentWillReceiveProps(nextProps) {
        // Calculate state according to props changes
        this.setState({
            isPassed: nextProps.score >= 60
        });
    }
}

The old props can be accessed via this.props inside componentWillReceiveProps(). Typically, you can set state according to changes of props in this method.

3.2 shouldComponentUpdate()

boolean shouldComponentUpdate(object nextProps, object nextState)

shouldComponentUpdate() will be invoked before rendering when new props or state are being received. This method won’t be called on initial rendering.

shouldComponentUpdate() returns true by default.

This method is usually an opportunity to prevent the unnecessary re-rendering considering performance. Just let shouldComponentUpdate() return false, then the render() method of the component will be completely skipped until the next props or state change.

class SinglePlayer extends React.Component {
    shouldComponentUpdate(nextProps, nextState) {
        // Don't rerender if score doesn't change, 
        if ( nextProps.score == this.props.score ) {
            return false;
        }

        return true;
    }
}

3.3 componentWillUpdate()

void componentWillUpdate(object nextProps, object nextState)

Invoked just before render(), but after shouldComponentUpdate() (of course, return a true). This method is not called for the initial rendering.

Use this as an opportunity to prepare for an update.

class SinglePlayer extends React.Component {
    componentWillUpdate(nextProps, nextState) {
        alert('componentWillUpdate => ' + this.props.name);
        console.log('componentWillUpdate => ' + this.props.name);
    }
}

3.4 componentDidUpdate()

void componentDidUpdate(object prevProps,object prevState)

Invoked immediately after the component’s updates are flushed to the DOM. This method is not called for the initial rendering.
You can perform DOM operations after an update inside this function.

class SinglePlayer extends React.Component {
    componentDidUpdate(prevProps, prevState) {
        alert('componentDidUpdate => ' + this.props.name);
        console.log('componentDidUpdate => ' + this.props.name);
    }
}

4 Unmounting

void componentWillUnmount()
This is invoked immediately before a component is unmounted or removed from the DOM.

Use this as an opportunity to perform cleanup operations. For example, unbind event listeners here to avoid memory leaking.

class ScoreBoard extends React.Component {
    componentWillUnmount() {
        window.removeEventListener('scroll', this._handleScroll);
    }
}

5 Sample codes

Complete sample codes to log each lifecycle method call in browser’s console.

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>React Component Lifecycle Demo</title>
    <!-- react includes two parts: react.js and react-dom.js -->
    <script src="//fb.me/react-15.2.1.js"></script>
    <script src="//fb.me/react-dom-15.2.1.js"></script>

    <!-- babel standalone -->
    <script src="//cdnjs.cloudflare.com/ajax/libs/babel-standalone/6.10.3/babel.min.js"></script>
</head>
<body>
    <div id="app"></div>

    <script type="text/babel">
        const tom_and_jerry = [
            {
                name: 'Tom',
                score: 55
            },
            {
                name: 'Jerry',
                score: 80
            }
        ];

        class SinglePlayer extends React.Component {
            constructor(props) {
                super(props);
                this.state = { isPassed: false }
            }
            componentWillMount() {
                // Mark it as 'Pass' if score >= 60
                this.setState({
                    isPassed: this.props.score >= 60
                });

                console.log('componentWillMount => ' + this.props.name);
                alert('componentWillMount => ' + this.props.name);
            }
            componentDidMount() {
                console.log('componentDidMount => ' + this.props.name);
                alert('componentDidMount => ' + this.props.name);
            }
            componentWillReceiveProps(nextProps) {
                // Calculate state according to props changes
                this.setState({
                    isPassed: nextProps.score >= 60
                });

                console.log('componentWillReceiveProps => ' + this.props.name + ': ' + nextProps.score);
                alert('componentWillReceiveProps => ' + this.props.name + ': ' + nextProps.score);
            }
            shouldComponentUpdate(nextProps, nextState) {
                // Don't rerender if score doesn't change,
                if ( nextProps.score == this.props.score ) {
                    console.log('shouldComponentUpdate => ' + this.props.name + '? false');
                    alert('shouldComponentUpdate => ' + this.props.name + '? false');
                    return false;
                }

                console.log('shouldComponentUpdate => ' + this.props.name + '? true');
                alert('shouldComponentUpdate => ' + this.props.name + '? true');
                return true;
            }
            componentWillUpdate(nextProps, nextState) {
                console.log('componentWillUpdate => ' + this.props.name);
                alert('componentWillUpdate => ' + this.props.name);
            }
            componentDidUpdate(prevProps, prevState) {
                console.log('componentDidUpdate => ' + this.props.name);
                alert('componentDidUpdate => ' + this.props.name);
            }
            componentWillUnmount() {
                console.log('componentDidUpdate => ' + this.props.name);
                alert('componentDidUpdate => ' + this.props.name);
            }
            render() {
                console.log("render => " + this.props.name);
                return (
                    <div>
                        <h5><span>Name: </span>{this.props.name}</h5>
                        <p><span>Score: </span><em>{this.props.score}</em></p>
                        <p><span>Pass: </span><input type="checkbox" defaultChecked={this.state.isPassed} disabled={true}  /></p>
                    </div>
                );
            }
        }

        class ScoreBoard extends React.Component {
            constructor(props) {
                super(props);
                this.state = {
                    players: tom_and_jerry
                };
            }
            changeScore(amount) {
                if ( typeof(amount) != "number" ) {
                    return;
                }

                let players = this.state.players;
                let tom = players[0];
                tom.score = tom.score + amount;

                tom.score = (tom.score > 100) ? 100 : tom.score;
                tom.score = (tom.score < 0) ? 0 : tom.score;

                players[0] = tom;
                this.setState({ players: players });
            }
            render() {
                return (
                    <div>
                        <h4>Score Board</h4>
                        <div>
                            <button onClick={ (amount) => this.changeScore(5) }>Score of Tom: +5</button>
                            <button onClick={ (amount) => this.changeScore(-5) }>Score of Tom: -5</button>
                        </div>
                        {
                            this.state.players.map((v, idx) => {
                                return <SinglePlayer key={idx} name={v.name} score={v.score} />
                            })
                        }
                    </div>
                );
            }
        }



        class App extends React.Component {
            render() {
                return (
                    <div>
                        <h1>React Component Lifecycle Demo</h1>
                        <ScoreBoard />
                    </div>
                )
            }
        }

        // Mount root App component
        ReactDOM.render(<App />, document.getElementById('app'));
    </script>
</body>
</html>
  • STATE: is an Mutable Object, which is initialized in component.
  • if we do changes in state. our entire component will get re-render
  • PROPS: iss an immutable object, we can not edit it , it will come form parent class, to pass data from parent to child class we can use it
  • SUPER: to inherit parent class object, we use Super into the constructor, to use the props we have to pass props into super(props)
  • we should use this.state only within the constructor method
  • getDerivedStateFromProps() this static method get two arguments<(nextprops, previousState) and it can either return Object or null/li>
  • componentDidMount() here API calls can happen, before this life cycle method we should not do API Calls. We can modify state object this.setState({…}).
    if we do changes in state, it will call rerender before that it call getDerivedStateFromProps
  • After that it will call shouldComponentUpdate(nextProps, nextState) it return either true/false. Based on this our component will decide either render or not
  • After render call, then getSnapShotBeforeUpdate() will call (prevProps, previouState), it return null/value/object
  • After that componentDidUpdate(prevProps, previousState, snapshot) all three values will be available. we can invoke API Calls
  • Before component Destroy , it will call componentWillUnmount. if any action to do before component destroy, we can use this
export default class App extends React.Component{
	constructor(props){
		super(props);
		this.state = {
			count: 0;
		}
	}
	
	static getDerivedStateFromProps(nextProps, previousState) {
		return null
	}
	
	render () {
		return {
			
				Hello
			
		}
	}
	
	componentDidMount() {
		//API Call
		this.setState({
			count: 1
		})
	}
	shouldComponentUpdate(nextProps, nextState){
		return true;
	}
	
	getSnapshotBeforeUpdate(prevProps, previousState){
		return null
	}
	
	componentDidUpdate(prevProps, previousState, snapshot){
		//API
	}
	
	componentWillUnmount(){
		//Before destorying the component
	}
}

Reference

codevoila

react-lifecycles
the_life_cycle_recap
guides

Leave a Reply

Your email address will not be published. Required fields are marked *