Reactjs componentDidUpdate是否在更新所有子项后运行?

Reactjs componentDidUpdate是否在更新所有子项后运行?,reactjs,Reactjs,我想知道React组件的生命周期方法componentDidUpdate是在所有子级的render方法完成后执行,还是在调用该组件的render方法后立即执行 由于协调器递归调用render方法来更新视图,我有一种预感,componentdiddupdate会在重新呈现组件的所有子级之后执行,但是在视图中没有足够的信息。什么时候调用了componentdiddupdate?不确定是否有更深入的文档,但确实很容易自己测试 class Nested extends React.Component {

我想知道React组件的生命周期方法
componentDidUpdate
是在所有子级的
render
方法完成后执行,还是在调用该组件的
render
方法后立即执行


由于协调器递归调用
render
方法来更新视图,我有一种预感,
componentdiddupdate
会在重新呈现组件的所有子级之后执行,但是在视图中没有足够的信息。什么时候调用了componentdiddupdate?

不确定是否有更深入的文档,但确实很容易自己测试

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"));
类嵌套扩展React.Component{
建造师(道具){
超级(道具);
this.state={foo:undefined};
}
render(){
log(“Rendered”+this.props.name);
返回{this.setState({foo:Date.now()}}}>Update{this.props.name}{this.props.children?React.cloneElement(React.children.only(this.props.children)){foo:this.state.foo}):未定义}
}
componentDidUpdate(){
console.log(“更新”+this.props.name);
}
}
ReactDOM.render(,document.getElementById(“app”);

更新外部组件会导致最内部的
componentdiddupdate
首先运行,然后是最外部的。更新内部组件只会导致该组件更新


有趣的是,
render
函数正好相反。首先呈现外部组件,然后呈现内部组件。

在执行组件的
render
方法后,调用
componentdiddupdate
方法。这意味着它将在所有子级的
render
方法完成后调用。您链接的文档中暗示了这一点:

当组件已更新时,利用此机会在DOM上操作。

该组件仅在渲染后更新,因此文档表明它是在所有子组件(因此是父组件)完成重新渲染(尽管如此)后调用的。只有当DOM完成更新、子对象和所有对象时,才能真正对其进行操作


例如,假设我们有两个组件,
A
B
B
呈现
A
组件<
B
的code>componentdiddupdate仅在
B
渲染完成后调用。
B
render
将在成功调用
A
render
后完成,因为子对象是父对象的一部分,因此首先呈现。这意味着您的问题的答案是:
componentdiddupdate
在所有子级的
渲染完成后执行。

正如@Andrew Li正确指出的那样,
componentdiddupdate
在所有子级渲染完成后执行。尽管如此,从那时起,React的光纤调节算法(16.0版以后)可能已经改变了以前的假设

简而言之,React将工作分为两个阶段,即
呈现
(首先执行)阶段和
提交
(在
呈现
之后执行)阶段
componentDidUpdate
属于
commit
阶段,是在此阶段中调用的最后一个生命周期方法(在
GetSnapshotForeUpdate
之后,
componentWillUnmount
componentDidMount
),因此总是在呈现节点及其子节点之后发生

渲染
阶段以“深度优先”遍历方式遍历光纤树,如图所示(取自高度推荐的渲染阶段)

(子节点水平显示,因此
c1
b2
的子节点,
b3
b2
的同级节点,而
b1
没有任何子节点。)

此外,组件可能会重新渲染(例如,在状态更改、HOC、已连接的道具等之后),这不会触发父级上的
componentdiddupdate
。我认为情况一直如此,甚至在v16.0之前

综上所述,我认为对子组件的呈现进行假设是不寻常的(可能是不安全的),会在这些组件之间产生不必要的耦合,并建议每个组件都具有足够的模块化,不依赖于其父组件的
componentdiddupdate
或其子组件的
render()
。如果需要通知父级,子级(ren)已完成渲染,可以将函数作为道具传递,然后在
componentdiddupdate
componentDidMount
(或
useffect
)中调用该道具


沙盒:

添加一些日志到父
componentdiddupdate
方法,并添加一些子类的
render
方法,看看哪一个是先输出的。生命周期方法首先为子类调用,然后为父类调用,对吗?但这是否在任何地方都有正式的文档记录?此主题是否会更改?您将在render方法的开始处记录render。内部渲染将在外部渲染完成之前完成。@AndyRay说得很好。但是我想没有其他方法可以做到这一点,因为你不能在render函数返回后记录。但是你可以写:
render(){console.log(“开始渲染”+this.props.name);const retVal={this.setState({foo:Date.now()}}}>Update{this.props.name}{this.props.children?React.cloneElement(React.children.only(this.props.children),{foo:this.state.foo}):未定义};console.log(“结束呈现”+this.props.name);return retVal;}
对于那些寻找官方文档的人: