A look at the React Lifecycle

Every react component is required to provide a render function. It can return false or it can return elements but it needs to be there. If you providing a single function, it’s assumed to be a render function:

const Foo = ({thing}) => <p>Hello {thing}</p>
<Foo thing="world" />

There has been a fair bit written about the chain of lifecycle methods that React calls leading up to it’s invocation of the render function and afterwards. The basic order is this:

constructor
render
componentDidMount

But things are rarely that simple, and often this.setState is called in componentDidMount which gives a call chain that looks like this:

constructor
render
componentDidMount
shouldComponentUpdate
componentWillUpdate
render
componentDidUpdate

Nesting components inside each other adds another wrinkle to this, as does my use of ES6/7, which adds a few subtle changes to the existing lifecycle methods. To get this sorted out in my own head, I created two classes: an Owner and and Ownee.

class Owner extends React.Component {

  // ES7 Property Initializers replace getInitialState
  //state = {}

  // ES6 class constructor replaces componentWillMount
  constructor(props) {
    super(props)
    console.log("Owner constructor")
    this.state = {
      foo: "baz"
    }
  }

  componentWillReceiveProps(nextProps) {
    console.log("Owner componentWillReceiveProps")
  }

  shouldComponentUpdate(nextProps, nextState) {
    console.log("Owner shouldComponentUpdate")
    return true
  }

  componentWillUpdate(nextProps, nextState) {
    console.log("Owner componentWillUpdate")
  }

  shouldComponentUpdate(nextProps, nextState) {
    console.log("Owner shouldComponentUpdate")
    return true
  }

  render() {
    console.log("Owner render")
    return (
      <div className="owner">
        <Ownee foo={ this.state.foo } />
      </div>
    )
  }

  componentDidUpdate(nextProps, nextState) {
    console.log("Owner componentDidUpdate")
  }

  componentDidMount() {
    console.log("Owner componentDidMount")
  }

  componentWillUnmount() {
    console.log("Owner componentWillUnmount")
  }

}

A component is said to be the owner of another component when it sets it’s props. A component whose props are being set is an ownee, so here is our Ownee component:

class Ownee extends React.Component {

  // ES6 class constructor replaces componentWillMount
  constructor(props) {
    super(props)
    console.log("  Ownee constructor")
  }

  componentWillReceiveProps(nextProps) {
    console.log("  Ownee componentWillReceiveProps")
  }

  shouldComponentUpdate(nextProps, nextState) {
    console.log("  Ownee shouldComponentUpdate")
    return true
  }

  componentWillUpdate(nextProps, nextState) {
    console.log("  Ownee componentWillUpdate")
  }

  render() {
    console.log("  Ownee render")
    return (
        <p>Ownee says {this.props.foo}</p>
    )
  }

  componentDidUpdate(nextProps, nextState) {
    console.log("  Ownee componentDidUpdate")
  }

  componentDidMount() {
    console.log("  Ownee componentDidMount")
  }

  componentWillUnmount() {
    console.log("  Ownee componentWillUnmount")
  }

}

This gives us the following chain:

Owner constructor
Owner render
  Ownee constructor
  Ownee render
  Ownee componentDidMount
Owner componentDidMount

Adding this.setState({foo: "bar"}) into the Owner’s componentDidMount gives us a more complete view of the call chain:

Owner constructor
Owner render
  Ownee constructor
  Ownee render
  Ownee componentDidMount
Owner componentDidMount
Owner shouldComponentUpdate
Owner componentWillUpdate
Owner render
  Ownee componentWillReceiveProps
  Ownee shouldComponentUpdate
  Ownee componentWillUpdate
  Ownee render
  Ownee componentDidUpdate
Owner componentDidUpdate

Things definitely get more complicated when components start talking to each other and passing functions that setState but the basic model is reassuringly straight forward. The changes that ES6/7 bring to the React lifecycle are relatively minor but nonetheless nice to have clear in my head as well.
If you want to explore this further I’ve created a JSbin.

Advertisements