我对React中的构造函数有疑问
在https://codesandbox.io/s/lpr147kmyl上查看示例
import React from "react";
import ReactDOM from "react-dom";
import "./styles.css";
class SimpleComponent extends React.Component {
constructor(props) {
super(props);
this.state = {
number: props.number,
}
console.log('constructor', this.state.number)
}
render() {
return (
<div>
{this.props.number}
</div>
)
}
}
class App extends React.Component {
constructor(props){
super(props)
this.state = {
showFirstComponent: true,
}
setInterval(() => (
this.setState(previousState => (
{ showFirstComponent: !previousState.showFirstComponent }
))
), 1000);
}
render(){
let c1 = <SimpleComponent number="1" />
let c2 = <SimpleComponent number="2" />
return (
<div className="App">
<h1>
{this.state.showFirstComponent ? c1 : c2}
</h1>
</div>
);
}
}
const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
我检查了控制台日志,只看到一条日志消息。 我以为在创建两个SimpleComponent实例时应该是两条日志消息:
let c1 = <SimpleComponent number="1" />
let c2 = <SimpleComponent number="2" />
我的问题是:
当React创建新的组件实例并调用组件的构造函数时?
谢谢
答案 0 :(得分:1)
您的三元组正在检查showFirstComponent
的状态,并且仅呈现一个状态。
{this.state.showFirstComponent ? c1 : c2}
如果将它们全部删除,只需执行
<SimpleComponent number="1" />
<SimpleComponent number="2" />
您将获得两个日志。为了进一步回答这个问题,constructor
在挂载组件时被调用,通常是一次,除非您是动态挂载东西。回到您的三元组:
{this.state.showFirstComponent ? c1 : c2}
如果您要通过按钮切换this.state.showFirstComponent
,请说:
<button onClick={() => this.setState({
showFirstComponent: !this.state.showFirstComponent
})>
Toggle c1/c2
</button>
每次单击该按钮时,组件将被卸载,而另一个将被安装,因此您将获得控制台日志。安装和卸载之间的顺序为react lifecycle methods。但是,如果您执行其他任何操作(例如,更改传递的道具,更改<SimpleComponent />
的内部组件状态),则会不卸载,而是进行更新,这将调用render方法,并且不是构造函数。建议您在console.log
中为某些生命周期方法添加<SimpleComponent />
并尝试触发它们,以更好地了解组件生命周期。或read an article about it。
答案 1 :(得分:1)
根据the doc,constructor
仅在安装组件之前被调用。如果在代码示例中添加两个以上的React Lifecycle函数:componentDidMount
和componentWillUnmount
,您将看到该组件在整个过程中仅安装了一次,而无论状态改变的时间如何。如果然后将shouldComponentUpdate
添加到组件,您将看到SimpleComponent
仅存在一个实例,并且上级状态更改显示为SimpleComponent
上的道具更改。>
在这里看不到两个实例正在安装和卸载的原因是,变量c1
和c2
通常是SimpleComponent
的 not 实例,方便地假设。相反,它们是ReactElement,它是组件实例的描述。
React中的主要类型是ReactElement。它具有四个属性:type,props,key和ref。它没有方法,原型上也没有。
仅当呈现元素时,才会创建组件的实例,并在它们各自的时间点调用constructor
和Lifecycle函数。
那么,为什么在您的示例中,元素c2
从未被用来创建组件?这可以追溯到React如何决定在特定时间何时更新什么(您可以阅读有关here的更多信息:
当组件更新时,实例保持不变,因此在渲染之间保持状态。
在您的示例中,当App
组件呈现c2
而不是c1
时,React看到新的组件元素与旧的组件元素相同,因此它重用了该组件(即仅存在一个实例),并相应地更新道具/状态。
以下是我发现对理解此问题有用的更多阅读材料: https://developmentarc.gitbooks.io/react-indepth/content/life_cycle/birth_mounting_indepth.html
马克·阿默里(Mark Amery)对this question的回答也很有帮助。
答案 2 :(得分:1)
如果某人因反应本地而来到这里。
为不同的实例分配不同的keys
将创建新的实例,而不是重复使用同一实例。
<MyComponent
key={this.state.uniqueInstanceKey}
myData={this.state.myData}/>