【譯】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組件,反之亦然。

相關文章
相關標籤/搜索