React:函数调用在 render() 之后和 child 的构造函数()之前
React: Function call after render() and before child's constructor()
我有一个名为 Parent 的组件,其中还有另一个名为 Child 的组件:
<Parent>
<Child/>
</Parent>
所以生命周期如下:
- Parent构造函数
- Parent 的 render()
- Child构造函数
- Child 的 render()
- Child已挂载
- Parent已挂载
我可以在第 2 步之后和第 3 步之前以某种方式进行额外的 Parent 初始化吗?
更新:
class ThirdPartyLib {
init(elementId) {
console.log(`initializing element: ${elementId}`);
// element with #id: elementId should exist!
// document.getElementById(elementId).style.color = "red";
}
}
class Parent extends React.Component {
constructor(props) {
super(props);
console.log("Parent's constructor");
}
render() {
console.log("rendering Parent");
new ThirdPartyLib().init("parent");
return (
<div id="parent">Parent: {this.props.name}
<Child name="Sara"/>
</div>
);
}
componentDidMount() {
console.log("Parent is mounted");
}
}
class Child extends React.Component {
constructor(props) {
super(props);
console.log(`Child ${this.props.name} constructor`);
}
render() {
console.log(`rendering Child: ${this.props.name}`);
return <div>Child: {this.props.name}</div>
}
componentDidMount() {
console.log(`Child ${this.props.name} is mounted`);
}
}
ReactDOM.render(<Parent name="Bob"/>, document.getElementById("app"));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
<div id="app"></div>
这里我做了一些简化 - 我不仅仅是改变元素的颜色,我本可以在 componentDidMount()
方法中完成。相反,ThirdPartyLib
细节决定了初始化顺序。在 Parent 出现在 DOM 中之后,我必须在创建任何 child 元素之前对其进行初始化。
更具体地说,Parent
和 Child
共享 ThirdPartyLib
class 的完全相同的实例。我无法将初始化逻辑放入 Parent 的 render()
函数中,因为该元素还不在 DOM 中。同样,我无法按照 componentDidMount()
评论中的建议在 Child
之前初始化 Parent
,因为 Child
的 componentDidMount()
在 [= 之前执行16=]的。
解决这个问题的一种方法是延迟渲染子项,直到父项挂载之后。步骤如下所示:
- 初始父级渲染不渲染子级(例如,在父级状态下使用标志抑制)
- 父级
componentDidMount
执行第三方初始化并更改父级状态中的标志,触发父级的重新渲染
- Parent 的重新渲染现在将渲染 Child 并且 Parent 可以通过 prop 将第三方初始化信息传递给 Child
生成的代码类似于:
import React from "react";
import ReactDOM from "react-dom";
class ThirdPartyLib {
init(elementId) {
console.log(`initializing element: ${elementId}`);
this.element = document.getElementById(elementId);
this.element.style.color = "red";
}
}
class Parent extends React.Component {
constructor(props) {
super(props);
this.state = { initialized: false };
console.log("Parent's constructor");
}
render() {
console.log("rendering Parent");
return (
<div id="parent">
Parent: {this.props.name}
{this.state.initialized && (
<Child name="Sara" thirdPartyLib={this.state.thirdPartyLib} />
)}
</div>
);
}
componentDidMount() {
console.log("Parent is mounted");
const thirdPartyLib = new ThirdPartyLib();
thirdPartyLib.init("parent");
this.setState({ initialized: true, thirdPartyLib });
}
}
class Child extends React.Component {
constructor(props) {
super(props);
console.log(`Child ${this.props.name} constructor`);
console.log(
`Child knows stuff from thirdPartyLib: ${
this.props.thirdPartyLib.element.id
}`
);
}
render() {
console.log(`rendering Child: ${this.props.name}`);
return (
<div>
Child: {this.props.name}
<br />
ThirdPartyLib element id:
{this.props.thirdPartyLib.element.id}
</div>
);
}
componentDidMount() {
console.log(`Child ${this.props.name} is mounted`);
}
}
const rootElement = document.getElementById("root");
ReactDOM.render(<Parent name="Bob" />, rootElement);
我有一个名为 Parent 的组件,其中还有另一个名为 Child 的组件:
<Parent>
<Child/>
</Parent>
所以生命周期如下:
- Parent构造函数
- Parent 的 render()
- Child构造函数
- Child 的 render()
- Child已挂载
- Parent已挂载
我可以在第 2 步之后和第 3 步之前以某种方式进行额外的 Parent 初始化吗?
更新:
class ThirdPartyLib {
init(elementId) {
console.log(`initializing element: ${elementId}`);
// element with #id: elementId should exist!
// document.getElementById(elementId).style.color = "red";
}
}
class Parent extends React.Component {
constructor(props) {
super(props);
console.log("Parent's constructor");
}
render() {
console.log("rendering Parent");
new ThirdPartyLib().init("parent");
return (
<div id="parent">Parent: {this.props.name}
<Child name="Sara"/>
</div>
);
}
componentDidMount() {
console.log("Parent is mounted");
}
}
class Child extends React.Component {
constructor(props) {
super(props);
console.log(`Child ${this.props.name} constructor`);
}
render() {
console.log(`rendering Child: ${this.props.name}`);
return <div>Child: {this.props.name}</div>
}
componentDidMount() {
console.log(`Child ${this.props.name} is mounted`);
}
}
ReactDOM.render(<Parent name="Bob"/>, document.getElementById("app"));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
<div id="app"></div>
这里我做了一些简化 - 我不仅仅是改变元素的颜色,我本可以在 componentDidMount()
方法中完成。相反,ThirdPartyLib
细节决定了初始化顺序。在 Parent 出现在 DOM 中之后,我必须在创建任何 child 元素之前对其进行初始化。
更具体地说,Parent
和 Child
共享 ThirdPartyLib
class 的完全相同的实例。我无法将初始化逻辑放入 Parent 的 render()
函数中,因为该元素还不在 DOM 中。同样,我无法按照 componentDidMount()
评论中的建议在 Child
之前初始化 Parent
,因为 Child
的 componentDidMount()
在 [= 之前执行16=]的。
解决这个问题的一种方法是延迟渲染子项,直到父项挂载之后。步骤如下所示:
- 初始父级渲染不渲染子级(例如,在父级状态下使用标志抑制)
- 父级
componentDidMount
执行第三方初始化并更改父级状态中的标志,触发父级的重新渲染 - Parent 的重新渲染现在将渲染 Child 并且 Parent 可以通过 prop 将第三方初始化信息传递给 Child
生成的代码类似于:
import React from "react";
import ReactDOM from "react-dom";
class ThirdPartyLib {
init(elementId) {
console.log(`initializing element: ${elementId}`);
this.element = document.getElementById(elementId);
this.element.style.color = "red";
}
}
class Parent extends React.Component {
constructor(props) {
super(props);
this.state = { initialized: false };
console.log("Parent's constructor");
}
render() {
console.log("rendering Parent");
return (
<div id="parent">
Parent: {this.props.name}
{this.state.initialized && (
<Child name="Sara" thirdPartyLib={this.state.thirdPartyLib} />
)}
</div>
);
}
componentDidMount() {
console.log("Parent is mounted");
const thirdPartyLib = new ThirdPartyLib();
thirdPartyLib.init("parent");
this.setState({ initialized: true, thirdPartyLib });
}
}
class Child extends React.Component {
constructor(props) {
super(props);
console.log(`Child ${this.props.name} constructor`);
console.log(
`Child knows stuff from thirdPartyLib: ${
this.props.thirdPartyLib.element.id
}`
);
}
render() {
console.log(`rendering Child: ${this.props.name}`);
return (
<div>
Child: {this.props.name}
<br />
ThirdPartyLib element id:
{this.props.thirdPartyLib.element.id}
</div>
);
}
componentDidMount() {
console.log(`Child ${this.props.name} is mounted`);
}
}
const rootElement = document.getElementById("root");
ReactDOM.render(<Parent name="Bob" />, rootElement);