1

I'm trying to understand react lifecycle hooks and have faced a problem with componentDidMount() lifecycle hook.

Suppose you are rendering a list of components. componentDidMount() method for each list item is always fired at the end after all list items have rendered. Why it did not fire at the beginning for each item?

This is my render() method in my root App component

  render() {
    return (
      <div className="App">
        <A>
          <A1 />
          <A2 />
        </A>
        <B>
          <B1 />
          <B2 />
        </B>
      </div>
    );
  }
}

structure of a single component A,A1,A2,B,B1,B2 all looks the same, only the name is different.

import React, { Component } from "react";

class A extends Component {
  constructor(props) {
    super(props);

    this.state = {};

    console.log(" [A.js] constructor()");
  }

  componentWillMount() {
    console.log(" [A.js] ComponentWillMount()");
  }

  componentDidMount() {
    console.log(" [A.js] ComponentDidMount()");
  }

  render() {
    console.log(" [A.js] render()");
    return <div>{this.props.children}</div>;
  }
}

export default A;

and I have written console logs inside each method in all components. And below is a screenshot of I got. https://snag.gy/wyi5Ta.jpg

in the screenshot we get

[App.js] constructor()
[App.js] componentWillMount()
[App.js] render()
 [A.js] constructor()
 [A.js] ComponentWillMount()
 [A.js] render()
  [A1.js] constructor()
  [A1.js] ComponentWillMount()
  [A1.js] render()
  [A2.js] constructor()
  [A2.js] ComponentWillMount()
  [A2.js] render()
 [B.js] constructor()
 [B.js] ComponentWillMount()
 [B.js] render()
  [B1.js] constructor()
  [B1.js] ComponentWillMount()
  [B1.js] render()
  [B2.js] constructor()
  [B2.js] ComponentWillMount()
  [B2.js] render()
  [A1.js] ComponentDidMount()
  [A2.js] ComponentDidMount()
 [A.js] ComponentDidMount()
  [B1.js] ComponentDidMount()
  [B2.js] ComponentDidMount()
 [B.js] ComponentDidMount()
[App.js] componentDidMount()

i was expecting

[App.js] constructor()
[App.js] componentWillMount()
[App.js] render()
 [A.js] constructor()
 [A.js] ComponentWillMount()
 [A.js] render()
  [A1.js] constructor()
  [A1.js] ComponentWillMount() <---
  [A1.js] render()
  [A1.js] ComponentDidMount()
  [A2.js] constructor()
  [A2.js] ComponentWillMount() <---
  [A2.js] render()
  [A2.js] ComponentDidMount()
 [A.js] ComponentDidMount() <---
 [B.js] constructor()
 [B.js] ComponentWillMount()
 [B.js] render()
  [B1.js] constructor()
  [B1.js] ComponentWillMount()
  [B1.js] render()
  [B1.js] ComponentDidMount() <---
  [B2.js] constructor()
  [B2.js] ComponentWillMount()
  [B2.js] render()
  [B2.js] ComponentDidMount() <---
 [B.js] ComponentDidMount()
[App.js] componentDidMount()

I have put arrows where I expected the componentDidMount() method to fire. What's the reason for this?

I couldn't find the exact answer to this question. I also found that react follows "Depth First Search" traversal method. I watched some videos, but couldn't understand this mystery. Can someone please explain? I have been struggling hours now to figure this out. Thanks.

dmcshehan
  • 1,109
  • 7
  • 14

1 Answers1

0

The constructor for a React component is called before it is mounted.

https://reactjs.org/docs/react-component.html#constructor

UNSAFE_componentWillMount() is invoked just before mounting occurs. It is called before render(), therefore calling setState() synchronously in this method will not trigger an extra rendering.

https://reactjs.org/docs/react-component.html#unsafe_componentwillmount

componentDidMount() is invoked immediately after a component is mounted (inserted into the tree).

https://reactjs.org/docs/react-component.html#componentdidmount

Everything happens as expected according to documentation. [B.js] render() is simply called before [A1.js] has been inserted into the tree. Remove [B.js] and children and it will work anyway.

The important thing is that the parent componentDidMount is called after the children's are mounted, otherwise it's would be impossible to e.g. calculate the parent node's height because it's still empty when componentDidMount is fired.

https://github.com/facebook/react/issues/14753

https://blog.bitsrc.io/understanding-asynchronous-javascript-the-event-loop-74cd408419ff

Ogglas
  • 62,132
  • 37
  • 328
  • 418