componentDidMount
生命周期方法是否与同级组件无关?从下面的示例看来,只有在安装了所有同级组件之后,才会调用它。
假设我们有一个顶层组件,它呈现2个子组件,第一个具有简单的render()
,另一个具有相对较慢的render()
。
要复制的样本:https://codesandbox.io/s/j43klml9py?expanddevtools=1
TL; DR:
class SlowComponent extends Component {
componentDidMount() {
// perf mark
}
render() {
// Simulate slow render
// Takes 50ms
return <h3>Slow component</h3>;
}
}
class FastComponent extends Component {
componentDidMount() {
// perf mark
}
render() {
return <h3>Fast component</h3>;
}
}
class App extends Component {
constructor(props) {
super(props);
// perf mark start
}
componentDidMount() {
// perf mark
// measure all marks and print
}
render() {
return (
<div>
<FastComponent />
<SlowComponent />
</div>
);
}
}
ReactDOM.render(<App />, document.getElementById('root'));
我希望componentDidMount
的时间像这样:
FastComponent
10毫秒SlowComponent
50毫秒App
52毫秒但是实际上,我得到的是同时触发快速和慢速组件componentDidMount
回调,即
FastComponent
50毫秒SlowComponent
51毫秒App
52毫秒当前的示例代码和repro代码使用挂载回调,但对componentDidUpdate
也适用。
完整来源:
import ReactDOM from "react-dom";
import React, { Component } from "react";
class SlowComponent extends Component {
componentDidMount() {
performance.mark("slow-mounted");
}
render() {
// Simulate slow render
for (var i = 0; i < 10000; i++) {
for (var j = 0; j < 100; j++) {
const b = JSON.parse(
JSON.stringify({
test: "test" + i,
test1: i * i * i
})
);
}
}
return <h3>Slow component</h3>;
}
}
class FastComponent extends Component {
componentDidMount() {
performance.mark("fast-mounted");
}
render() {
return <h3>Fast component</h3>;
}
}
class App extends Component {
constructor(props) {
super(props);
performance.mark("init");
}
componentDidMount() {
performance.mark("app-mounted");
performance.measure("slow", "init", "slow-mounted");
performance.measure("fast", "init", "fast-mounted");
performance.measure("app", "init", "app-mounted");
console.clear();
console.log(
"slow",
Math.round(performance.getEntriesByName("slow")[0].duration)
);
console.log(
"fast",
Math.round(performance.getEntriesByName("fast")[0].duration)
);
console.log(
"app",
Math.round(performance.getEntriesByName("app")[0].duration)
);
performance.clearMarks();
performance.clearMeasures();
}
render() {
return (
<div>
<h1>Demo</h1>
<FastComponent />
<SlowComponent />
</div>
);
}
}
ReactDOM.render(<App />, document.getElementById("root"));
答案 0 :(得分:5)
我假设您使用的是最新的React版本(16.5.0)。
假设将两个组件(一个慢速组件和一个快速组件)包装在父组件中,则执行流程如下:
UNSAFE_componentWillMount
方法UNSAFE_componentWillMount
方法render
方法(此处将使用耗时缓慢的昂贵组件的渲染方法)componentDidMount
方法componentDidMount
方法这整个过程是同步进行的。
回到您的示例,这就是为什么两个组件的计时几乎相同的原因,因为所有组件的工作一旦完成,所有组件生命周期方法就会被调用。
通常,从概念上讲,React由两个阶段组成,即“渲染”阶段和“提交”阶段。
“提交”阶段是React应用任何更改的阶段,在您的示例中,生命周期方法componentDidMount
在此阶段被调用。
您可以通过调试React并查看以下堆栈跟踪来遵循此流程:
componentDidMount
commitLifeCycles
commitAllLifeCycles
callCallback
invokeGuardedCallbackDev
invokeGuardedCallback
commitRoot
答案 1 :(得分:1)
简单答案
所有渲染完成后,所有组件都会触发componentDidMount
方法。因为在将元素安装到DOM之前,我们需要创建它们。
答案 2 :(得分:1)
根据您的生命周期顺序,将在挂载组件后调用componentDidMount(顾名思义,这本身就是暗示)。这将在DOM挂载之后进行,这将调用您的渲染。
现在假设是否没有I / O,即在任何地方的子组件中都发生了异步事件。
(即使发生任何异步事件,这些函数也会被执行,但调用堆栈将在事件循环中保持执行。但这是一个单独的讨论)
-- Parent
-- Child-1
-- Child-2
执行顺序
Parent constructor()
Child 1 constructor()
Child 1 render()
Child 1 componentDidMount()
Child 2 constructor()
Child 2 render()
Child 2 componentDidMount()
Parent componentDidMount()
根据ReactJS文档,安装触发器的顺序为
参考React文档Mounting React Docs中的安装顺序
在旁注中,另有详细说明了执行顺序。 Understanding React — Component life-cycle
答案 3 :(得分:0)
是的,ComponentDidMount生命周期方法独立于同级组件。这取决于渲染所花费的时间,因为它会在渲染完成后调用。但是组件的安装顺序与父组件中的安装顺序相同。例如-在上面的示例中,首先安装快速组件,然后安装第二个组件。
您无法计算函数迭代一个循环所花费的时间。因此,这里您对计算慢速组件的ComponentDidMount生命周期方法的时间的假设是错误的。如果不进行概要分析,则无法期望基于迭代次数的特定时间估计。