Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

lifecycle: componentWillReceiveProps called before componentDidMount

Tags:

reactjs

If I understand correctly the React lifecycle of a Component should make sure that componentDidMount is called before componentWillReceiveProps. When I test this on the initial mount of a component it seems to work that way. But when the component is has already been mounted before and is remounted the order is the other way around. Is this the expected behavior? The following piece of code illustrates a potential bug that could be introduced this way:

class Example extends React.Component {
    componentDidMount() { 
        this.something = { foo: 'bar' };
    }
    componentWillReceiveProps(nextProps) {
        this.something.foo;
        // Throws a TypeError if this code is reached before
        // componentDidMount is called.
    }
}
like image 287
Matthisk Avatar asked May 24 '16 10:05

Matthisk


People also ask

What comes before componentDidMount?

componentDidMount. The componentDidMount() method is called after the component is rendered. This is where you run statements that requires that the component is already placed in the DOM.

Which is called first componentDidMount or componentWillMount?

componentDidMount() is only called once, on the client, compared to componentWillMount() which is called twice, once to the server and once on the client. It is called after the initial render when the client received data from the server and before the data is displayed in the browser.

What is the replacement for componentWillReceiveProps?

The useEffect hook is also the equivalent of the componentWillReceiveProps or componentDidUpdate hooks. All we have to do is to pass in an array with the value that we want to watch for changes.

Is componentDidUpdate called on first render?

ComponentDidUpdate() is invoked immediately after updating occurs and is not called for the initial render. The most common use-case for the componentDidUpdate () lifecycle method is updating the DOM in response to Prop or State changes.


1 Answers

The short answer:
The order of firing these methods is indeed not guaranteed. Which is one of the reasons why (as in your example) using component variables outside props and state is not a good idea.

Better: put your { foo: 'bar' } in state if you need to use it beyond lifecycle events.

The longer answer:

componentDidMount() is only called once for each lifecycle:

  • after the first render (NB: after all children have also rendered, and after all children have also called their componentDidMounts)
  • if the component is rendered after it has been unmounted (but this really is a new lifecycle)

componentWillReceiveProps() is NOT called on first render in lifecycle, but is called on all following renders = when the parent sends props again.

Normally, the second render (triggering) componentWillReceiveProps will come after the component (and its children) have finished mounting, so after componentDidMount().

But I can think of at least 1 (maybe theoretical) scenario where the order will reversed:

  1. Component receives props, and starts rendering.
  2. While component is rendering, but has not yet finished rendering, component receives new props.
  3. componentWillReceiveProps() is fired, (but componentDidMount has not yet fired)
  4. After all children and component itself have finished rendering, componentDidMount() will fire.

So componentDidMount() is not a good place to initialise component-variables like your { foo: 'bar' }.
componentWillMount() would be a better lifecycle event.
However, I would discourage any use of component-wide variables inside react components, and stick to design principles:

  • all component variables should live in either state or props (and be immutable)
  • all other variables are bound by the lifecycle method (and not beyond that)
like image 96
wintvelt Avatar answered Oct 27 '22 00:10

wintvelt