Bug: componentDidMount fires before lazy-loaded components are mounted
See original GitHub issueIn a component with child components that are lazy loaded using React.lazy, the component’s componendDidMount() callback is fired before the lazy-loaded children are loaded/mounted. This makes it very difficult to perform logic on child components (eg. calling a component method via a ref, using ReactDOM.findDOMNode on the children, etc.) in componentDidMount. This all obviously works fine with components that are synchronously loaded but makes it very difficult to migrate an existing React application using synchronously loaded components to one that leverages React.lazy.
This behavior is observed with React version 16.12.
The issue can be illustrated with code like this:
import React, {Suspense} from 'react';
import ReactDOM from 'react-dom';
const SomeComponent = React.lazy(() => import("./SomeComponent"));
class Comp extends React.Component {
constructor() {
super();
this.compRef = React.createRef();
}
componentDidMount() {
this.compRef.current.blur();
}
render() {
return
<Suspense fallback={<div>Loading...</div>} >
<SomeComponent ref={this.compRef} />
</Suspense>
}
}
ReactDOM.render(<Comp/>, document.createElement("div"))
The current behavior
The current behavior is that the componentDidMount callback is fired before the lazy loaded component is rendered/mounted so using compRef fails.
The expected behavior
The componentDidMount method should only fire once all of the child components have loaded/mounted. Or, there should be some other way to consolidate code that performs operations on asynchronously loaded/rendered components.
Issue Analytics
- State:
- Created 4 years ago
- Comments:8 (2 by maintainers)
Not really a bug but it is always implied that the suspended component will always fail first due to asynchronicity and so
Suspense
will always render the fallback, hence the render method is successful (since the pending/failing component is handled gracefully) then thecomponentDidMount
is called. This is certainly the intended behavior.Yeah there’s not much we can do here. If we did like you described (e.g. wait for all child components) then this would cut out a huge amount of use cases — e.g. focusing a text field like
and it would always be dangerous to add
lazy
deeply because that would break assumptions.In general,
findDOMNode
is not a recommended pattern anyway — whether incomponentDidMount
or anywhere else. This is precisely because you won’t get notified about what arbitrary children do. You can use callback refs for this instead.