我想知道在所有子项的componentDidUpdate
方法完成之后,或者在调用该组件的render
方法之后,是否执行了React组件的生命周期方法render
由于协调程序以递归方式调用render
方法来更新视图,因此我预感到componentDidUpdate
在重新呈现组件的所有子项后执行,但是没有足够的信息documentation。什么时候调用componentDidUpdate
?
答案 0 :(得分:13)
在组件的componentDidUpdate
方法执行完毕后调用render
方法。这意味着它将在所有孩子的render
方法完成后调用。这在您链接的文档中暗含着:
将此作为在更新组件时对DOM 进行操作的机会。
组件仅在渲染后更新,因此文档暗示它在所有子节点之后调用,因此父节点已完成重新渲染(尽管a bit unclear)。只有在完成更新,子项和所有内容时,您才能对DOM进行操作。
例如,假设我们有两个组件,A
和B
,B
呈现A
组件。 componentDidUpdate
的{{1}}只会在B
B
完成后调用。 render
render
的{{1}}将在成功调用B
A
后完成,因为孩子由于是父母的一部分而首先呈现。这意味着您的问题的答案是:render
在所有孩子componentDidUpdate
完成后执行。
答案 1 :(得分:5)
不确定某处是否有更深入的文档,但确实很容易自行测试。
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
更新外部组件会导致最里面的componentDidUpdate
先运行,然后运行最外面的render
。更新内部组件只会导致该组件更新。
有趣的是,它与 <form name="form1" method="post" enctype="multipart/form-data" action="api/upload">
...
<div>
<label for="folderName">Folder Name</label>
<input name="folderName" type="text" />
</div>
<div>
<label for="images">Images</label>
<!-- you choose multiple files -->
<input name="images" type="file" multiple />
</div>
...
</form>
函数相反。外部组件首先渲染,然后渲染内部组件。
答案 2 :(得分:1)
正如@Andrew Li正确指出的那样,componentDidUpdate
在所有子级都被渲染之后执行。尽管这种情况仍然存在,但是从那时起,React的光纤和解算法(从16.0版开始)可能已经改变了先前的假设。
简而言之,React将工作分为两个阶段,render
(首先执行)阶段和commit
(render
之后执行)阶段。 componentDidUpdate
属于commit
阶段,是此阶段中调用的最后一个生命周期方法(在getSnapshotBeforeUpdate
,componentWillUnmount
和componentDidMount
之后),因此将始终在节点及其子节点的渲染。
render
阶段以这种“深度优先”的遍历方式遍历了光纤树(如强烈推荐的Inside Fiber: in-depth overview of the new reconciliation algorithm in React所示)。
(水平示出了子节点,因此c1
是b2
的子节点,而b3
是b2
的同级节点,而b1
则不是没有孩子。)
此外,组件可能会重新渲染(例如,在状态更改,HOC,连接的道具等之后),这不会在父对象上触发componentDidUpdate
。我认为即使在v16.0之前,情况总是如此。
基于以上所述,我认为对子组件的呈现进行假设是不寻常的(并且可能是不安全的),并且会在这些组件之间造成不必要的耦合,并建议每个组件都足够模块化而不依赖于其父组件。 componentDidUpdate
或其子代的render()
。如果您需要通知父母孩子已经完成渲染,则可以传递一个作为道具的函数,然后在componentDidUpdate
或componentDidMount
(或useEffect
)内部调用该函数。