Does componentDidUpdate run after all children have been updated?
As @Andrew Li correctly pointed out, componentDidUpdate
is executed after all children have been rendered. While this still stands, since then, React's Fiber reconciliation algorithm (version 16.0 onwards) may have changed previous assumptions.
In a nutshell, React divides the work into two phases, the render
(executed first) phase and the commit
(executed after render
) phase. componentDidUpdate
falls under the commit
phase and is the last lifecycle method called in this phase (after getSnapshotBeforeUpdate
, componentWillUnmount
and componentDidMount
) and will therefore always occur after the rendering of a node and its children.
The render
phase traverses the Fiber tree as a "depth-first" traversal as illustrated in this image (taken from the highly recommended Inside Fiber: in-depth overview of the new reconciliation algorithm in React).
(child nodes are illustrated horizontally, so c1
is a child of b2
and b3
is a sibling node of b2
, while b1
doesn't have any children.)
Additionally, a component may re-render (for example, following a state change, HOC, connected props...etc) and this will not trigger a componentDidUpdate
on the parent. I think this was always the case, even before v16.0.
With the above being said, I believe it is unusual (and possibly unsafe) to make assumptions on the rendering of child components and would create unnecessary coupling between these components and recommend that each component is modular enough to not depend on its parent's componentDidUpdate
or its child's render()
. If you need to inform a parent that a child(ren) has finished rendering, you may pass a function as a prop which is then called inside componentDidUpdate
or componentDidMount
(or useEffect
).
Sandbox: https://codesandbox.io/s/react-rendering-tr59s
The componentDidUpdate
method is called after the render
method of the component is done executing. That means that it will be called after all children's render
methods have finished. This is implied in the documentation you linked:
Use this as an opportunity to operate on the DOM when the component has been updated.
The component is only updated post-render, so the documentation implies that it's called after all children, and consequently the parent, have finished rerendering (albeit a bit unclear). You can only really operate on the DOM when it finishes updating, children and all.
For example, say we have two components, A
and B
and B
renders a A
component. componentDidUpdate
for B
will only be called once B
's render
finishes. The render
of B
will finish after A
's render
is successfully called because children are rendered first due to being part of the parent. That means the answer to your question is: componentDidUpdate
is executed after all the children's render
s have completed.
Not sure if there is more in-depth documentation somewhere, but it is indeed easy enough to test on your own.
class Nested extends React.Component {
constructor(props){
super(props);
this.state = {foo: undefined};
}
render() {
console.log("Rendered " + this.props.name);
return <div><button onClick={() => {this.setState({foo: Date.now()})}}>Update {this.props.name}</button>{this.props.children ? React.cloneElement(React.Children.only(this.props.children), {foo: this.state.foo}) : undefined}</div>
}
componentDidUpdate() {
console.log("Updated " + this.props.name);
}
}
ReactDOM.render(<Nested name="outer"><Nested name="inner"></Nested></Nested>, document.getElementById("app"));
http://jsbin.com/yiyuhegayo/edit?js,console,output
Updating the outer component results in the innermost componentDidUpdate
running first, and then the outermost. Updating the inner component only causes that component to update.
Interestingly, it is the opposite for the render
functions. The outer component renders first, then the inner one.