【译】State and Lifecycle (State和生命周期)

下面是react官方文档的我的翻译,若有翻译错误,请多多指出
原文地址:https://facebook.github.io/re...javascript

Consider the ticking clock example from one of the previous sections.
思考一下,咱们以前提到过的时钟例子。
So far we have only learned one way to update the UI.
到目前为止,咱们只学到一种更新UI的方式。
We call ReactDOM.render() to change the rendered output:
咱们调用ReactDOM.render()的方法来改变渲染的输出:html

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);

打开试试java

In this section, we will learn how to make the Clock component truly reusable and encapsulated.
在这一章,咱们会学到怎么把Clock组件变得真正的可重用以及封装。
It will set up its own timer and update itself every second.
这会让配置咱们的timer组件而且每秒自我更新。react

We can start by encapsulating how the clock looks:
咱们从怎么封装Clock开始:git

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);

打开试试github

However, it misses a crucial requirement: the fact that the Clock sets up a timer and updates the UI every second should be an implementation detail of the Clock.
然而,这会错过一个相当重要的需求: Clock设置一个计时器而且每秒钟更新UI是一个时钟的实现细节。数组

Ideally we want to write this once and have the Clock update itself:
理想情况下,咱们先写一次而后这个Clock能自我更新:浏览器

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

To implement this, we need to add "state" to the Clock component.
要实现这一点,咱们须要添加“state” 到 Clock组件。app

State is similar to props, but it is private and fully controlled by the component.
stateporps很类似,可是这是组件私有的而且是受组件控制的。less

We mentioned before that components defined as classes have some additional features.
咱们在前面说起过,用类的形式定义组件有一些额外的功能。

Local state is exactly that: a feature available only to classes.
本地state就是:只有一个特征类。

Converting a Function to a Class

将一个函数转换为一个类

You can convert a functional component like Clock to a class in five steps:
你能经过五步把一个函数组件转化为类组件

  1. Create an ES6 class with the same name that extends React.Component. 建立一个同名的类组件而且继承React.Compoent

  2. Add a single empty method to it called render().添加一个空的方法叫作render()

  3. Move the body of the function into the render() method.把函数里面的内容移到render方法里面。

  4. Replace props with this.props in the render() body.把render()里面的props替换成this.props

  5. Delete the remaining empty function declaration.删掉以前的函数声明的组件。

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

打开试试

Clock is now defined as a class rather than a function.
Clock如今定义成一个类组件比定义成函数组件好。

This lets us use additional features such as local state and lifecycle hooks.
由于这让咱们添加一些新的功能例如本地state以及生命周期。

Adding Local State to a Class

添加State

We will move the date from props to state in three steps:
咱们将用三步把props移到state

1) Replace this.props.date with this.state.date in the render() method:
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>
    );
  }
}

2) Add a class constructor that assigns the initial this.state:
添加class constructor 用来初始化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>
    );
  }
}

Note how we pass props to the base constructor:
注意,咱们是怎么把props传递到constructor的:

constructor(props) {
    super(props);
    this.state = {date: new Date()};
  }

Class components should always call the base constructor with props.
类组件应该调用constructor时候带着props

3) Remove the date prop from the <Clock /> element:
<Clock />中的 date props移除掉:

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

We will later add the timer code back to the component itself.
咱们将会添加回定时器代码到组件自己。
The result looks like this:
结果以下:

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')
);

打开试试
Next, we'll make the Clock set up its own timer and update itself every second.
下一步,咱们将把组件功能本身设置定时器而且能每秒更新。

Adding Lifecycle Methods to a Class

添加周期方法到类组件

In applications with many components, it's very important to free up resources taken by the components when they are destroyed.
在有许多组件的应用里, 当组件被销毁的时候释放掉资源是很是重要的。

We want to set up a timer whenever the Clock is rendered to the DOM for the first time.
咱们想让Clock组件在第一次渲染在DOM的时候设置定时器。

This is called "mounting" in React.
咱们在React中称为"mounting"。

We also want to clear that timer whenever the DOM produced by the Clock is removed.
咱们一样当组件被移除的手请

This is called "unmounting" in React.
咱们在React中称为"unmounting"。

We can declare special methods on the component class to run some code when a component mounts and unmounts:
咱们在类组件里生命一些特别的方法当组件mountsunmounts的时候去运行一些代码:

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>
    );
  }
}

These methods are called "lifecycle hooks".
这些方法被称为“生命周期方法钩子"。

The componentDidMount() hook runs after the component output has been rendered to the DOM. This is a good place to set up a timer:
这个componentDidMount的方法会在组件渲染在dom上后被调用。这是一个设置定时器的好地方:

componentDidMount() {
    this.timerID = setInterval(
      () => this.tick(),
      1000
    );
  }

Note how we save the timer ID right on this.
注意咱们是怎么保存定时器ID的。

While this.props is set up by React itself and this.state has a special meaning, you are free to add additional fields to the class manually if you need to store something that is not used for the visual output.
this.props被初始化在React,并且 this.state有一个特殊的意义,你能够手动地自由地添加额外的字段到类中,若是你须要存储一些你不被用来输出渲染

If you don't use something in render(), it shouldn't be in the state.
若是你不使用render()方法,就不该该用在state里。

We will tear down the timer in the componentWillUnmount() lifecycle hook:
咱们将在componentWillUnmount这个生命周期的函数方法中卸载掉定时器:

componentWillUnmount() {
    clearInterval(this.timerID);
  }

Finally, we will implement the tick() method that runs every second.
最后,咱们会每一秒跑tick()方法。

It will use this.setState() to schedule updates to the component local state:
咱们会用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')
);

打开试试

Now the clock ticks every second.
如今,时钟每一秒都在转动。

Let's quickly recap what's going on and the order in which the methods are called:
让咱们快速回顾一下,发生了什么而且咱们是怎么去调用这些方法的。

1) When <Clock /> is passed to ReactDOM.render(), React calls the constructor of the Clock component.
<Clock />做为参数传递ReactDOM.render()的时候,React调用Clock组件中的constructor函数。
Since Clock needs to display the current time, it initializes this.state with an object including the current time.
因为Clock须要显示正确的时间,所以咱们初始化this.state成一个object包含这正确的时间。
We will later update this state.
咱们稍后会更新这个state
2) React then calls the Clock component's render() method. This is how React learns what should be displayed on the screen.
React 稍后会调用Clock组件的render()方法。这就是React怎样知道什么东西应该渲染到界面上。
React then updates the DOM to match the Clock's render output.
React 稍后会更新DOM来保证Clock正确的渲染输出
3) When the Clock output is inserted in the DOM, React calls the componentDidMount() lifecycle hook.
Clock输出被插入到DOM里面,React会调用componentDidMount()的方法。
Inside it, the Clock component asks the browser to set up a timer to call tick() once a second.
以后,Clock组件会在浏览器里设置定时器而且开始tick()方法。

4) Every second the browser calls the tick() method.
每一秒浏览器调用tick方法。
Inside it, the Clock component schedules a UI update by calling setState() with an object containing the current time.
在里面,Clock组件会安排一个UI经过调用setState()而且传入一个时间的对象来更新。
Thanks to the setState() call, React knows the state has changed, and calls render() method again to learn what should be on the screen.
因为setState()调用,React知道state的改变,而且再次调用render()方法来让界面知道怎么改变。
This time, this.state.date in the render() method will be different, and so the render output will include the updated time.
这一次,this.state.datarender()方法将会不同,因此渲染接输出讲包括更新时间。
React updates the DOM accordingly.
React相应地更新DOM。

5) If the Clock component is ever removed from the DOM, React calls the componentWillUnmount() lifecycle hook so the timer is stopped.
若是Clock组件要从DOM外移除,React会调用componentWillUnmount()函数,而且是定时器中止。

Using State Correctly

正确使用State

There are three things you should know about setState().
有三件关于的setState的事你必须知道

Do Not Modify State Directly

别直接修改State的值

For example, this will not re-render a component:
例如,这不会从新渲染一个组件:

// Wrong
this.state.comment = 'Hello';

Instead, use setState():
咱们要用setState()来代替:

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

The only place where you can assign this.state is the constructor.
你惟一能声明this.state的地方只有在constructor里

State Updates May Be Asynchronous

State的更新有多是异步的

React may batch multiple setState() calls into a single update for performance.
React 为了性能,可能会把批量处理屡次的setState() 调用在一个的更新里。

Because this.props and this.state may be updated asynchronously, you should not rely on their values for calculating the next state.
由于this.propsthis.state可能异步更新了,你不该该依赖他们的值来计算下一个state

For example, this code may fail to update the counter:
例如, 下面的代码可能会更新计算器失败:

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

To fix it, use a second form of setState() that accepts a function rather than an object.
为了解决这个问题,让setState()接收一个函数比接收一个对象的方式更好。
That function will receive the previous state as the first argument, and the props at the time the update is applied as the second argument:
这个函数会把前一个state做为第一个参数, 而且props在那时更新并被做为第二参数:

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

We used an arrow function above, but it also works with regular functions:
咱们在上面的函数用了箭头函数,咱们使用常规的函数也同样可用:

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

State Updates are Merged

state的更新是合并后的

When you call setState(), React merges the object you provide into the current state.
当你调用setState(),React会合并你提供的对象到当前的state里。

For example, your state may contain several independent variables:
例如:你的state可能包含几个独立的变量:

constructor(props) {
    super(props);
    this.state = {
      posts: [],
      comments: []
    };
  }

Then you can update them independently with separate setState() calls:
而后你就能独立更新他们经过单独调用setState()

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

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

The merging is shallow, so this.setState({comments}) leaves this.state.posts intact, but completely replaces this.state.comments.
这个合并是浅合并,因此this.setState({comments})会让this.state.posts完整,可是会彻底替换掉this.state.comments.

The Data Flows Down

单向数据流

Neither parent nor child components can know if a certain component is stateful or stateless, and they shouldn't care whether it is defined as a function or a class.

全部的父组件或者子组件都不知道一个组件是stateful或者stateless的,而且他们也不该该关心本身是被定义成一个函数或者是类组件。

This is why state is often called local or encapsulated. It is not accessible to any component other than the one that owns and sets it.
这就是为何state常常被本地调用或者被封装。对于别的组件来讲,组件的拥有的state是不可被访问的。

A component may choose to pass its state down as props to its child components:
一个组件可能会把本身的state做为props传递给他们的子组件中:

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

This also works for user-defined components:
这一样适用用户定义的组件中:

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

The FormattedDate component would receive the date in its props and wouldn't know whether it came from the Clock's state, from the Clock's props, or was typed by hand:
FormattedDate组件将会接收data做为他的props而且将不知道他是来自哪,是Clock's state,是来自Clock's state, 仍是来自手动输入的。

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

打开试试

This is commonly called a "top-down" or "unidirectional" data flow. Any state is always owned by some specific component, and any data or UI derived from that state can only affect components "below" them in the tree.
这就是咱们日常所说的从上往下或者单向数据流。任何的state都是属于一些特定的组件,而且任何的数据或者UI视图 只能影响在他组件树下面的的组件。

If you imagine a component tree as a waterfall of props, each component's state is like an additional water source that joins it at an arbitrary point but also flows down.
若是你把一个组件的props想象成是瀑布,每个组件的state就像一个额外的水资源,而且这在任意点处连接还往下流。

To show that all components are truly isolated, we can create an App component that renders three <Clock>s:
为了展现全部的组件都是孤立的,咱们建立一个App组件来渲染三个<Clock>组件:

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

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

打开试试

Each Clock sets up its own timer and updates independently.
每一个Clock都会独立设置以及更新本身的定时器。

In React apps, whether a component is stateful or stateless is considered an implementation detail of the component that may change over time.
在React app里,不管一个stateful or stateless的组件都被认为组件独立的细节均可能随着时间而改变。

You can use stateless components inside stateful components, and vice versa.
你能用stateless组件代替stateful组件,反之亦然。

相关文章
相关标签/搜索