当React创建新的组件实例时?

时间:2019-01-30 01:11:39

标签: reactjs constructor

我对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创建新的组件实例并调用组件的构造函数时?

谢谢

3 个答案:

答案 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 docconstructor仅在安装组件之前被调用。如果在代码示例中添加两个以上的React Lifecycle函数:componentDidMountcomponentWillUnmount,您将看到该组件在整个过程中仅安装了一次,而无论状态改变的时间如何。如果然后将shouldComponentUpdate添加到组件,您将看到SimpleComponent仅存在一个实例,并且上级状态更改显示为SimpleComponent上的道具更改。

在这里看不到两个实例正在安装和卸载的原因是,变量c1c2通常是SimpleComponent not 实例,方便地假设。相反,它们是ReactElement,它是组件实例的描述

  

React中的主要类型是ReactElement。它具有四个属性:type,props,key和ref。它没有方法,原型上也没有。

     

React (Virtual) DOM Terminology

仅当呈现元素时,才会创建组件的实例,并在它们各自的时间点调用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}/>