# 状态和生命周期

我们有一个时钟组件,它接受外部参数传入的时间,将其显示。

function Clock(props) {
  return (
    <div>
      <h1>Hello, world!</h1>
      <h2>It is {props.date.toLocaleTimeString()}.</h2>
    </div>
  );
}
export default Clock;

我们需要定时的调用render()来更新显示的事件。

import Clock from "./components/Clock";
const root = ReactDOM.createRoot(document.getElementById('root'));

function tick() {
  root.render(<Clock date={new Date()} />);
}
setInterval(tick, 1000);

理想情况下,我们希望只编写一次代码,便可以让 Clock 组件自我更新。

我们需要在 Clock 组件中添加 “state” 来实现这个功能

# 改写为 Class 组件

// src/components/Clock.jsx
import React from "react";

class Clock extends React.Component {
  render() {
    return (
      <div>
        <h1>Hello, world!</h1>
        <h2>It is {this.props.date.toLocaleTimeString()}.</h2>
      </div>
    );
  }
}

export default Clock;

# 添加 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>
    );
  }
}

# 添加生命周期

class Clock extends React.Component {
  constructor(props) {
    super(props);
    this.state = {date: new Date()};
  }
  // life circle
  // like vue mounted
  componentDidMount() {
    this.timerID = setInterval(
      () => this.tick(),
      1000
    );
  }
  // like vue beforeDestory
  componentWillUnmount() {
    clearInterval(this.timerID);
  }
  // methods
  tick() {
    // 使用 this.setState() 来时刻更新组件 state
    this.setState({
      date: new Date()
    });
  }
  // render
  render() {
    return (
      <div>
        <h1>Hello, world!</h1>
        <h2>It is {this.state.date.toLocaleTimeString()}.</h2>
      </div>
    );
  }
}
import Clock from "./components/Clock";
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(<Clock/>);

# 正确地使用 State

# 不要直接修改 State

// 例如,此代码不会重新渲染组件
// Wrong
this.state.comment = 'Hello';
// 而是应该使用 setState():
// Correct
this.setState({comment: 'Hello'});

构造函数是唯一可以给 this.state 赋值的地方。

# State 的更新可能是异步的

出于性能考虑,React 可能会把多个 setState() 调用合并成一个调用。(运行时优化)

例如,此代码可能会无法更新计数器:

// Wrong
this.setState({
  counter: this.state.counter + this.props.increment,
});

要解决这个问题,可以让 setState() 接收一个函数而不是一个对象。这个函数用上一个 state 作为第一个参数。

// Correct
this.setState((state, props) => ({
  counter: state.counter + props.increment
}));

由于函数的闭包,所以此时参数的值得以被保存。

# State 的更新会被合并

当你调用 setState() 的时候,React 会把你提供的对象合并到当前的 state。

故而我们可以分别调用 setState() 来单独地更新它们

  componentDidMount() {
    fetchPosts().then(response => {
      this.setState({
        posts: response.posts // change post
      });
    });

    fetchComments().then(response => {
      this.setState({
        comments: response.comments // change comments
      });
    });
  }