据我所知,当某些事件发生时,React 从头开始创建一个虚拟 DOM,并将其与旧的虚拟 DOM 进行比较。如果是这种情况,那么在调用 render 方法时,react 应该创建组件并返回它们进行比较。
import React, { Component, Fragment } from 'react';
import ReactDOM from 'react-dom';
import './index.css';
class Demo extends Component {
constructor(props) {
console.log("constructor called");
super(props);
this.state = { dummy: 1, };
}
render = () => <button onClick={this.props.onChange}> button </button>;
}
class App extends Component {
state = { num: 0, };
onChange = () => {
this.setState({ num: this.state.num+1 }); // mutate state to trigger a render
}
render() {
console.log("rendered");
return (
<Fragment>
<Demo onChange={this.onChange} />
</Fragment>
);
}
}
ReactDOM.render(
<React.StrictMode>
<App />
</React.StrictMode>,
document.getElementById('root')
);
快速控制台日志显示构造函数在第一次被调用以将 Demo
组件挂载到页面上。但是,后续渲染不会创建与旧虚拟 DOM 进行比较的新 Demo
对象(因为未调用构造函数)。
起初,我的理论是,当Demo
的构造函数被调用时,它会调用超级构造函数来检查是否已经存在具有相同props的类似对象。但在调用父构造函数之前移动 console.log("constructor called");
证明了情况并非如此。
所以我的问题是 react 如何知道不创建另一个对象?
答案 0 :(得分:1)
这里的关键是 Demo
没有卸载。当您第一次渲染应用程序时,它会渲染并挂载 Demo
组件并传递 onChange
道具。但是,当从 Demo 调用回调时,它会在 App 上设置状态。在 App 中调用 setState
不会卸载 Demo 组件,因此无需再次挂载。最初安装组件的时间是构造函数运行的时间。如果您在 App 组件上设置了一个开关,该开关只会在特定条件为真时在渲染中显示该组件,这将触发该组件卸载。
看看这个代码沙盒并玩一下:https://codesandbox.io/s/lifecycle-methods-vivn6?file=/src/Lifecycle.js。
此外,这是一个很酷的图表,可以了解正在发生的事情:https://projects.wojtekmaj.pl/react-lifecycle-methods-diagram/
主要关键是构造函数在组件挂载时运行。只有在组件从 DOM 中卸载然后重新安装时,它才会再次运行。