State&生命周期
function tick() {
const element = (
<div>
<h1>Hello, world!</h1>
<h2>It is {new Date().toLocaleTimeString()}.</h2>
</div>
);
ReactDOM.render(
element,
document.getElementById('root')
);
}
setInterval(tick, 1000);
我们可以从封装时钟的外观开始:
function Clock(props) {
return (
<div>
<h1>Hello, world!</h1>
<h2>It is {props.date.toLocaleTimeString()}.</h2>
</div>
);
}
function tick() {
ReactDOM.render(
<Clock date={new Date()} />,
document.getElementById('root')
);
}
setInterval(tick, 1000);
然而,它忽略了一个关键的技术细节:Clock 组件需要设置一个计时器,并且需要每秒更新 UI。
理想情况下,我们希望只编写一次代码,便可以让 Clock 组件自我更新:
ReactDOM.render(
<Clock />,
document.getElementById('root')
);
我们需要在 Clock 组件中添加 “state” 来实现这个功能。
State 与 props 类似,但是 state 是私有的,并且完全受控于当前组件。
将函数组件转换成class组件
通过以下五步将 Clock 的函数组件转成 class 组件:
- 创建一个同名的 ES6 class,并且继承于 React.Component。
- 添加一个空的 render()方法。
- 将函数体移动到 render()方法之中。
- 在 render()方法中使用this.props替换props。
- 删除剩余的空函数声明。
现在 Clock 组件被定义为 class,而不是函数。
每次组件更新时 render 方法都会被调用,但只要在相同的 DOM 节点中渲染 <Clock /> ,就仅有一个 Clock 组件的 class 实例被创建使用。这就使得我们可以使用如 state 或生命周期方法等很多其他特性。
向class组件中添加局部的state
我们通过以下三步将 date 从 props 移动到 state 中:
- 把 - render()方法中的- this.props.date替换成- this.state.date:- class Clock extends React.Component {
- render() {
- return (
- <div>
- <h1>Hello, world!</h1>
- <h2>It is {this.state.date.toLocaleTimeString()}.</h2>
- </div>
- );
- }
- }
 
- 添加一个 class 构造函数,然后在该函数中为 - this.state赋初值:- class Clock extends React.Component {
- constructor(props) {
- super(props);
- this.state = {date: new Date()};
- }
- render() {
- return (
- <div>
- <h1>Hello, world!</h1>
- <h2>It is {this.state.date.toLocaleTimeString()}.</h2>
- </div>
- );
- }
- }
 - 通过以下方式将 - props传递到父类的构造函数中:- constructor(props) {
- super(props);
- this.state = {date: new Date()};
- }
 - Class 组件应该始终使用 - props参数来调用父类的构造函数。
- 移除 - <Clock />元素中的- date属性:- ReactDOM.render(
- <Clock />,
- document.getElementById('root')
- );
 - 代码如下:- class Clock extends React.Component {
- constructor(props) {
- super(props);
- this.state = {date: new Date()};
- }
- render() {
- return (
- <div>
- <h1>Hello, world!</h1>
- <h2>It is {this.state.date.toLocaleTimeString()}.</h2>
- </div>
- );
- }
- }
- ReactDOM.render(
- <Clock />,
- document.getElementById('root')
- );
 - 将生命周期方法添加到Class中- 在具有许多组件的应用程序中,当组件被销毁时释放所占用的资源是非常重要的。 
 当- Clock组件第一次被渲染到 DOM 中的时候,就为其设置一个计时器。这在 React 中被称为“挂载(mount)”。
 同时,当 DOM 中- Clock组件被删除的时候,应该清除计时器。这在 React 中被称为“卸载(unmount)”。
 我们可以为 class 组件声明一些特殊的方法,当组件挂载或卸载时就会去执行这些方法:- class Clock extends React.Component {
- constructor(props) {
- super(props);
- this.state = {date: new Date()};
- }
- componentDidMount() {
- }
- componentWillUnmount() {
- }
- render() {
- return (
- <div>
- <h1>Hello, world!</h1>
- <h2>It is {this.state.date.toLocaleTimeString()}.</h2>
- </div>
- );
- }
- }
 - 这些方法叫做“生命周期方法”。 - componentDidMount()方法会在组件已经被渲染到 DOM 中后运行,所以,最好在这里设置计时器:- componentDidMount() {
- this.timerID = setInterval(
- () => this.tick(),
- 1000
- );
- }
 - 接下来把计时器的 ID 保存在 - this之中(- this.timerID)。
 尽管- this.props和- this.state是 React 本身设置的,且都拥有特殊的含义,但是其实你可以向 class 中随意添加不参与数据流(比如计时器 ID)的额外字段。
 我们会在- componentWillUnmount()生命周期方法中清除计时器:- componentWillUnmount() {
- clearInterval(this.timerID);
- }
 - 最后,我们会实现一个叫 - tick()的方法,- Clock组件每秒都会调用它。
 使用- this.setState()来时刻更新组件 state:- class Clock extends React.Component {
- constructor(props) {
- super(props);
- this.state = {date: new Date()};
- }
- componentDidMount() {
- this.timerID = setInterval(
- () => this.tick(),
- 1000
- );
- }
- componentWillUnmount() {
- clearInterval(this.timerID);
- }
- tick() {
- this.setState({
- date: new Date()
- });
- }
- render() {
- return (
- <div>
- <h1>Hello, world!</h1>
- <h2>It is {this.state.date.toLocaleTimeString()}.</h2>
- </div>
- );
- }
- }
- ReactDOM.render(
- <Clock />,
- document.getElementById('root')
- );
 - 现在时钟每秒都会刷新。 
 让我们来快速概括一下发生了什么和这些方法的调用顺序:
- 当 - <Clock />被传给- ReactDOM.render()的时候,React 会调用- Clock组件的构造函数。 因为- Clock需要显示当前的时间,所以它会用一个包含当前时间的对象来初始化- this.state。我们会在之后更新 state。
- 之后 React 会调用组件的 render()方法。这就是 React 确定该在页面上展示什么的方式。然后 React 更新 DOM 来匹配Clock渲染的输出。
- 当 Clock的输出被插入到 DOM 中后, React 就会调用ComponentDidMount()生命周期方法。在这个方法中,Clock组件向浏览器请求设置一个计时器来每秒调用一次组件的tick()方法。
- 浏览器每秒都会调用一次 tick()方法。 在这方法之中,Clock组件会通过调用setState()来计划进行一次 UI 更新。得益于setState()的调用,React 能够知道 state 已经改变了,然后会重新调用render()方法来确定页面上该显示什么。这一次,render()方法中的this.state.date就不一样了,如此以来就会渲染输出更新过的时间。React 也会相应的更新 DOM。
- 一旦 Clock组件从 DOM 中被移除,React 就会调用componentWillUnmount()生命周期方法,这样计时器就停止了。
 
 
                         
                                

