React JS Lifecycle methods

Lifecycle methods of any React component can be divided into three phases.

  • Mounting (i.e. Birth)
  • Updating (i.e. Grow)
  • Unmounting (i.e. Death)

These phases can be further divided into following methods.

  • Mounting (i.e. Birth)
    • Initialization & Construction
    • Pre-mounting with componentWillMount()

    • Component render()

    • Post-mount with componentDidMount()

  • Updating (i.e. Grow)
    • Updating and componentWillReceiveProps()

    • Using shouldComponentUpdate()

    • Tapping into componentWillUpdate()

    • Post-Render with componentDidUpdate()

  • Unmounting (i.e. Death)
    • Using componentWillUnmount()

 

Lets have these method in detail: –

  • Initialization & Construction: – During the initialization of the Component from the Element, the props and state are defined. How these values are defined that depends on whether you are using React.createClass()  or  extend React.Component.  the Element instance contains the current props  that are being passed to the Component instance.
import React from 'react';

class Person extends React.Component {
  render() {
    return (
      <div>{ this.props.name } (age: { this.props.age })</div>
    );
  }
}

Person.defaultProps = { age: 'unknown' };

export default Person;

The result of process, if we create a new instance without setting the age prop ex: <Person name="Bill" />, is 

Bill (age: unknown)

 

.

Once the props are defined, the Component instance configures the initial state. This process occurs in the construction of the instance itself. Like below…

import React from 'react';

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

  render() {
    return (
      <div>{ this.props.name } (age: { this.props.age })</div>
    );
  }
}

Person.defaultProps = { age: 'unknown' };

export default Person;

Note: – It is important to keep in mind that if we do not define a state in the constructor/getInitialState then the state will be undefined. Because the state is undefined and not an empty Object ({}), if you try to query the state later on this will be an issue.

  • Pre-mounting with componentWillMount(): The first true life cycle method called is componentWillMount(). This method is only called one time, which is before the initial render. Since this method is called before render() our Component will not have access to the Native UI (DOM, etc.). We also will not have access to the children refs, because they are not created yet. This is the method which is called to prepare the first render of the Components. This means we can start performing calculations or processes based on the prop values.
import React from 'react';
import classNames from 'classnames';

export default class Person extends React.Component {
  constructor(props) {
    super(props);
    this.state = { mode: undefined } ;
  }

  componentWillMount() {
    let mode;
    if (this.props.age > 70) {
      mode = 'old';
    } else if (this.props.age < 18) {
      mode = 'young';
    } else {
      mode = 'middle';
    }
    this.setState({ mode });
  }

  render() {
    return (
      <div className={ classNames('person', this.state.mode) }>
        { this.props.name } (age: { this.props.age })
      </div>
    );
  }
}

Person.defaultProps = { age: 'unknown' };

There could be number of usages of this method but I have used this block of code for calling my RESTful APIs.

  • Component render():  In render(), we create Elements (generally via JSX) and return them. We access the Component this.props and this.state and let these values derive how content should be generated. When we access this.state, any changes we made during componentWillMount() are fully applied. render() method is the only method which exist across life cycle methods of React Component. render() method is a pure method. What does that mean? That means we shouldn’t call setState(), query the Native UI or anything else that can mutate the existing state of the application. The reason why we should not because calling setState() inside render() will kick off  render() method again and that will become an endless calls.

React will also warn you if you try to access the Native UI elements in the render pass. like below…

render() {
  // BAD: Don't do this either!
  let node = ReactDOM.findDOMNode(this);
  return (
    <div className={ classNames('person', this.state.mode) }>
      { this.props.name } (age: { this.props.age })
    </div>
  );
}

 

  • Post-mount with componentDidMount():  The last step in the Birth/Mount life cycle phase is our post-mount access via componentDidMount(). This method is called once all our children Elements and our Component instances are mounted onto the Native UI. Similar to componentWillMount()componentDidMount() is only called one time. But unlike our other Birth/Mount methods, where we start at the top and work down, componentDidMount() works from the bottom up.
class Square extends React.Component {
  render() {
     console.log("In  Square render");
     return (<p>{this.props.name}</p>);
  }
  componentDidMount(){
    console.log("In componentDidMount of Square")
  }
}

class Game extends React.Component {
 
 componentDidMount(){
   console.log("In componentDidMount of Game")
 }
 render() {
   console.log("In render")
   return (

 

);
   }
}

ReactDOM.render(<Game />,document.getElementById('root') );

So the output in console will be

"In render"
"In componentDidMount of Square"
"In componentDidMount of Game"

The componentDidMount() method can be a helpful heavy lifter for our Components. One of the most common tasks is interacting with the Native UI . Unlike   componentWillMount() or render() we can now fully interact with the Native stack.

 

  • Updating and componentWillReceiveProps(): The first method available to us in update (growth) phase is componentWillReceiveProps(). This method is called when props are passed to the Component instance. Let’s dig a little deeper into what this means.

The most obvious example is when new props are passed to a Component. For example, we have a Form Compone nt and a Person Component. The Form Component has a single <input /> that allows the user to change the name by typing into the input.  componentWillReceivePropsis the first hook that allows us to look into the upcoming Update. Here we could extract the new props and update our internal state. If we have a state that is a calculation of multiple props, we can safely apply the logic here and store the result using this.setState().

Use this as an opportunity to react to a prop transition before render() is called by updating the state using this.setState(). The old props can be accessed via this.props. Calling this.setState() within this function will not trigger an additional render.

  • Using shouldComponentUpdate() The next method in the Update life cycle is shouldComponentUpdate(). This method allows your Component to exit the Update life cycle if there is no reason to apply a new render.  The  shouldComponentUpdate() method is the first real life cycle optimization method that we can leverage in React. We can look at our current and new props & state and make a choice if we should move on.

 

  • Tapping into componentWillUpdate()  Once we have determined that we do need to re-render in our Update phase, the componentWillUpdate()will be called. The method is passed in two arguments: nextProps and nextState. componentWillUpdate() is called every time a re-render is required, such as when this.setState() is called. Just like componentWillMount(), this method is called before render(). Because we have not rendered yet, our Component’s access to the Native UI (DOM, etc.) will reflect the old rendered UI. Unlike componentWillMount(), we can access refs but in general this is not recommended.

The componentWillUpdate() is a chance for us to handle configuration changes and prepare for the next render. If we want to access the old props or state, we can call this.props or this.state. We can then compare them to the new values and make changes/calculations as required. Unlike componentWillMount(), we should not call this.setState() here. The reason we do not call this.setState() is that the method triggers another componentWillUpdate(). If we trigger a state change in componentWillUpdate() we will end up in an infinite loop.

Some of the more common uses for componentWillUpdate() is to set a variable based on state changes (not using this.setState()), dispatching events or starting animations.

// dispatching an action based on state change
componentWillUpdate(nextProps, nextState) {
  if (nextState.open == true && this.state.open == false) {
    this.props.onWillOpen();
  }
}

 

  • Post-Render with componentDidUpdate()  the componentDidUpdate() is the Update version of componentDidMount(). Once again, we can access the Native UI stack, interact with our refs and if required start another re-render/update.  When componentDidUpdate() is called, two arguments are passed:   prevProps  and prevState. This is the inverse of   componentWillUpdate().   The passed values are what the values were, and this.propsand this.state are the current values. Just like componentDidMount(), the componentDidUpdate() is called after all of the children are updated.

One of the worst things to do is do an unchecked setState():

componentDidUpdate(prevProps, prevState) {
  // BAD: DO NOT DO THIS!!!
  let height = ReactDOM.findDOMNode(this).offsetHeight;
  this.setState({ internalHeight: height });
}

By default, our shouldComponentUpdate() returns true, so if we used the above code we would fall into an infinite render loop.

  • Using componentWillUnmount(): During this phase our component is Unmounted from the Native UI stack and is marked for Garbage Collection. This method allows us to do some cleanup before we are removed from the UI stack. Typically we want to reverse any setup we did in either   componentWillMount()  or  componentDidMount().

 

Sample JSFiddle. You can play with it and remove method as per you choice and can debug the method calling order.

 

This post will be updated in feature as well.

 

Hope this clear your doubts!!