Lifecycle Methods

Lifecycle Methods

The beauty of React is the splitting of complicated UI’s into little, bite-sized bits.

Through lifecycle methods, we can then control what happens when each tiny section of your app renders, updates, thinks about re-rendering, and when it disappears entirely.


componentDidMount()

This method runs after your component is mounted and ready to use.
Here is where you make your API calls. Tyler McGinnis explains why:

"You can’t guarantee the AJAX request won’t resolve before the component mounts. If it did, that would mean that you’d be trying to setState on an unmounted component, which not only won’t work, but React will yell at you for. Doing AJAX in componentDidMount will guarantee that there’s a component to update."

You can read more of his answer here.

During .componentDidMount() is also a good phase to do the following:

  • draw on a <canvas> element that you just rendered
  • initialize a *masonry grid layout from a collection of elements
  • add event listeners (window.addEventListender("keydown", e => console.log(e.which)))
  • Basically, here you want to do all the setup you couldn’t do without a DOM, and start getting all the data you need.

*Masonry is a JavaScript grid layout library. It repositions elements depending on how they best fit. That's why we're interested in React checking our collection

Most Common Use Case: Starting AJAX (Axios) calls to load in data for your component.


shouldComponentUpdate()


When we get new state or props, our component always updates, right?

Yes, unless we tell it not to. In the words of Tyler McGinnis again:

"shouldComponentUpdate() allows us to opt out of this reconciliation process for certain components (and their child components). Why would we ever want to do this? As mentioned above, “The end goal of reconciliation is to, in the most efficient way possible, update the UI based on new state”. If we know that a certain section of our UI isn’t going to change, there’s no reason to have React go through the trouble of trying to figure out if it should. By returning false from shouldComponentUpdate, React will assume that the current component, and all its child components, will stay the same as they currently are."

shouldComponentUpdate() should always return a boolean — an answer to the question, "should I re-render?" The default is that it always returns true.
But if you’re worried about wasted renders — shouldComponentUpdate is an awesome place to improve performance.


componentDidUpdate()

Here we can do the same stuff we did in componentDidMount — reset our masonry layout, redraw our canvas, change or add event listeners, etc.
Didn’t we redraw our canvas in componentWillReceiveProps?
Yes, we did. Here’s why: in componentDidUpdate, you don’t know why it updated.
So if our component is receiving more props than those relevant to our canvas, we don’t want to waste time redrawing the canvas every time it updates.
That doesn’t mean componentDidUpdate isn’t useful. To go back to our masonry layout example, we want to rearrange the grid after the DOM itself updates — so we use componentDidUpdate to do so.

Most Common Use Case: Updating the DOM in response to prop or state changes.


componentWillUnmount()

Before you remove a component, we can make any last minute changes.

Here you can cancel any outgoing network requests, or remove all event listeners associated with the component.

Basically, clean up anything to do that solely involves the component in question — when it’s gone, it should be completely gone.

Most Common Use Case: Cleaning up any leftover debris from your component.


componentWillReceiveProps()(deprecated)

This method is considered legacy and you should avoid them in new code:

After our component is rendered, it often times receives new props. Before it receives those props, componentWillReceiveProps() is called.

In this method, we have access to both the next props (via nextProps), and our current props (via this.props).

componentWillReceiveProps(nextProps){
    console.log(this.props)
}

We should check which props will change. Sometimes componentWillReceiveProps gets called when nothing's changed.

componentWillReceiveProps(nextProps){
    console.log(this.props)
}

One more caveat — .componentWillReceiveProps() is not called on initial render. Technically the component is receiving props, but there aren’t any old props to compare to, so React doesn't worry about it.

Most Common Use Case: Acting on particular prop changes to trigger state transitions.


componentWillUpdate()(deprecated)

This methods is considered legacy and you should avoid it in new code:

After .shouldComponentUpdate() either returns or defaults to true, the component will update, but we can do some more stuff before the component re-renders. This method is rarely used. It’s basically the same as .componentWillReceiveProps(), except you are not allowed to call this.setState().

Most Common Use Case: Used instead of componentWillReceiveProps on a component that also has shouldComponentUpdate


componentWillMount()(deprecated)

This methods is considered legacy and you should avoid it in new code:

React will call this method before any of your JSX in your render() function has rendered. This means there is nothing in the DOM to play with.

Sometimes people are tempted to connect to external API's during this phase. Making AJAX (Axios) calls and whatnot. DO NOT DO THIS. We'll get to the reason in the next section.

The componentWillMount() is a chance for us to handle configuration, update our state, and in general prepare for the first render. At this point, props and initial state are defined. We can safely query this.props and this.state, knowing with certainty they are the current values. This means we can start performing calculations or processes based on the prop values.


import React from 'react';
import classNames from 'classnames';

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' };

export default Person;

In the example above we call this.setState() and update our current state before render. If we need state values on calculations passed in props, this is where we should do the logic.

Conclusion

In an ideal world, we wouldn’t use lifecycle methods. All our rendering issues would be controlled via state and props.

But sometimes we need to have a little more control over how and when your component is updating. This is often because of API calls, third party packages, rendering stuff like Canvass.