React (2) -- State and Lifecycle

原文地址:https://facebook.github.io/react/docs/state-and-lifecycle.html

State类似于props,但它是私有的,完全由组件控制。

我们之前提到,定义为类的组件具有一些附加功能。 本地State就是这样:一个功能只适用于类。

一、Converting a Function to a Class

您可以通过五个步骤将functional component转换为class:

  1. 创建一个名称扩展为React.Component的ES6类。
  2. 添加一个名为render()的空方法。
  3. 将函数的主体移动到render()方法中。
  4. 在render()正文中用this.props替换道具。
  5. 删除剩余的空函数声明。

二、Adding Local State to a Class

我们采取三个步骤将date从props移到state:

1)在render()方法中将this.props.date替换为this.state.date;
2)添加分配初始this.state的类构造函数(class constructor);
3)从< Clock />元素中删除日期.

三、Adding Lifecycle Methods to a Class

当组件安装(mounts)和卸载(unmounts)时,我们可以在组件类上声明特殊的方法来运行一些代码:

//mounts
  componentDidMount() {
    this.timerID = setInterval(
      () => this.tick(),
      1000
    );
  }
  
//unmounts
  componentWillUnmount() {
    clearInterval(this.timerID);
  }

这些方法称为“生命周期挂钩(lifecycle hooks)”。

在组件输出已经渲染DOM之后,componentDidMount()挂钩运行。这是一个建立定时器的好地方。

虽然this.props由React本身设置,而this.state具有特殊的含义,但如果需要存储未用于可视输出的内容,则可以手动向类中添加其他字段。

如果您不在render()中使用某些东西,则不应该在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')
);

1)当< Clock />传递给ReactDOM.render()时,React调用Clock组件的构造函数。由于Clock需要显示当前时间,所以它将使用包含当前时间的对象来初始化this.state。我们稍后会更新此状态。

2)React然后调用Clock组件的render()方法。然后,React然后更新DOM以匹配Clock的渲染输出。

3)当Clock输出插入到DOM中时,React调用componentDidMount()生命周期钩子。在其中,Clock组件要求浏览器设置一个定时器来一次调用tick()。

4)浏览器每秒钟调用tick()方法。在其中,Clock组件通过使用包含当前时间的对象调用setState()来调度UI更新。由于setState()调用,React知道状态已经改变,并再次调用render()方法来了解屏幕上应该展示什么。这一次,render()方法中的this.state.date将不同,因此渲染输出将包含更新的时间。相应地更新DOM。

5)如果Clock钟组件从DOM中删除,则React会调用componentWillUnmount()生命周期钩子,以使定时器停止。

四、Using State Correctly

  1. 不要直接修改State,而是使用setState()方法。
// Wrong
this.state.comment = 'Hello';

// Correct
this.setState({comment: 'Hello'});

  1. State更新可能是异步的
// Wrong
this.setState({
  counter: this.state.counter + this.props.increment,
});

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

  1. State Updates are Merged

当您调用setState()时,React将您提供的对象合并到当前状态。

五、The Data Flows Down

父组件和子组件都不能知道某个组件是有状态还是无状态,并且它们不应该关心它是否被定义为函数或类。

State通常被称为局部或封装。除了拥有并设置它的组件之外,其他组件都不可以访问State。

组件可以选择将其State作为props传递给其子组件:
eg:

<h2>It is {this.state.date.toLocaleTimeString()}.</h2>

eg:

<FormattedDate date={this.state.date} />

function FormattedDate(props) {
  return <h2>It is {props.date.toLocaleTimeString()}.</h2>;
}

FormattedDate组件将在其props中收到日期,并且不知道它是来自Clock's state,来自Clock's props,还是手动键入.

这通常被称为“自顶向下”或“单向”数据流。 任何state始终由某个特定组件所有,并且从该状态导出的任何数据或UI只能影响树中“下方”的组件。

如果你想象一个组件树作为props的瀑布,每个组件的状态就像一个额外的水源,它连接在一个任意点,但也流下来。

为了表明所有组件都是真正隔离的,我们可以创建一个应用程序组件,呈现三个< Clock >:

function FormattedDate(props) {
  return <h2>It is {props.date.toLocaleTimeString()}.</h2>;
}

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>
        <FormattedDate date={this.state.date} />
      </div>
    );
  }
}

function App() {
  return (
    <div>
      <Clock />
      <Clock />
      <Clock />
    </div>
  );
}

ReactDOM.render(<App />, document.getElementById('root'));

在React应用程序中,组件是有状态还是无状态被认为是可能随时间而变化的组件的实现细节。 可以在有状态组件中使用无状态组件,反之亦然。

posted @ 2017-06-08 15:31  MiyaMiya  阅读(264)  评论(0)    收藏  举报