Reputation: 1032
I have a question about the constructor in React
Look at a example at 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);
I checked the console log and saw only one log message. I thought there should be two log messages there as I create two instances of SimpleComponent :
let c1 = <SimpleComponent number="1" />
let c2 = <SimpleComponent number="2" />
My question is:
When does React create new a component instance and calls the component's constructor?
Thanks,
Upvotes: 2
Views: 8685
Reputation: 6635
If someone has landed here for react-native.
Assigning different keys
for different instances will create new instances instead of reusing the same instance.
<MyComponent
key={this.state.uniqueInstanceKey}
myData={this.state.myData}/>
Upvotes: 4
Reputation: 2382
According to the doc, constructor
is only called before a component is mounted. If you add two more React Lifecycle functions to your code example: componentDidMount
and componentWillUnmount
, you'll see that the component only mounted once in the entire process, regardless of the times the state changes. If you then add shouldComponentUpdate
to the component, you'll see that there is only one instance of SimpleComponent
and the upper-level state change is shown as props change on SimpleComponent
.
The reason why you don't see two instances mounting and unmounting here is that variables c1
and c2
are not instances of SimpleComponent
as commonly and conveniently assumed. Instead, they are ReactElement, which is a description of the component instance.
The primary type in React is the ReactElement. It has four properties: type, props, key and ref. It has no methods and nothing on the prototype.
Only when the element gets rendered, an instance of the component gets created and constructor
and the Lifecycle functions get called at their respective time points.
So then why, as in your example, the element c2
never gets to be used to create a component? This goes back to how React decides when and what to update at a certain time (you can read more about it here:
When a component updates, the instance stays the same, so that state is maintained across renders.
In your example, when the App
component renders c2
instead of c1
, React sees that the new component element is the same as the old one so it reuses the component(i.e. only a single instance exists) and updates the props/states accordingly.
Here are some more readings that I find useful to understand this problem: https://developmentarc.gitbooks.io/react-indepth/content/life_cycle/birth_mounting_indepth.html
Mark Amery's answer to this question is also very helpful.
Upvotes: 4
Reputation: 1400
Your ternary is checking the state for showFirstComponent
and rendering only one.
{this.state.showFirstComponent ? c1 : c2}
If you remove that all together, and just do
<SimpleComponent number="1" />
<SimpleComponent number="2" />
You'll get two logs. To further answer the question, constructor
is called when the component is mounted, so usually once, unless you're dynamically mounting stuff. To get back at your ternary:
{this.state.showFirstComponent ? c1 : c2}
If you were to toggle this.state.showFirstComponent
with a button lets say:
<button onClick={() => this.setState({
showFirstComponent: !this.state.showFirstComponent
})>
Toggle c1/c2
</button>
Every time you hit this button, component will be unmounted, and another one mounted, so you'll get a console log. Here's the order of react lifecycle methods between mount and unmount. However, if you do anything else, eg change the props passed, change the internal component state of <SimpleComponent />
, it will NOT unmount, but rather, update, which calls the render method, and not the constructor. I suggest adding a console.log
for some lifecycle methods in your <SimpleComponent />
and trying to trigger them, to better understand the component lifecycle. Or read an article about it.
Upvotes: 1