资讯专栏INFORMATION COLUMN

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

dadong / 1561人阅读

摘要:结果如下打开试试下一步,我们将把组件功能自己设置定时器并且能每秒更新。这是一个设置定时器的好地方注意我们是怎么保存定时器的。我们将在这个生命周期的函数方法中卸载掉定时器最后,我们会每一秒跑方法。

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

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()的方法来改变渲染的输出:

function tick() {
  const element = (
    

Hello, world!

It is {new Date().toLocaleTimeString()}.

); ReactDOM.render( element, document.getElementById("root") ); } setInterval(tick, 1000);

打开试试

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组件并且每秒自我更新。

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

function Clock(props) {
  return (
    

Hello, world!

It is {props.date.toLocaleTimeString()}.

); } function tick() { ReactDOM.render( , document.getElementById("root") ); } setInterval(tick, 1000);

打开试试

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(
  ,
  document.getElementById("root")
);

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

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

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:
你能通过五步把一个函数组件转化为类组件

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

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

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

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

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

class Clock extends React.Component {
  render() {
    return (
      

Hello, world!

It is {this.props.date.toLocaleTimeString()}.

); } }

打开试试

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 (
      

Hello, world!

It is {this.state.date.toLocaleTimeString()}.

); } }

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 (
      

Hello, world!

It is {this.state.date.toLocaleTimeString()}.

); } }

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 element:
中的 date props移除掉:

ReactDOM.render(
  ,
  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 (
      

Hello, world!

It is {this.state.date.toLocaleTimeString()}.

); } } ReactDOM.render( , 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 (
      

Hello, world!

It is {this.state.date.toLocaleTimeString()}.

); } }

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 (
      

Hello, world!

It is {this.state.date.toLocaleTimeString()}.

); } } ReactDOM.render( , 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 is passed to ReactDOM.render(), React calls the constructor of the Clock component.
作为参数传递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传递给他们的子组件中:

It is {this.state.date.toLocaleTimeString()}.

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

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 

It is {props.date.toLocaleTimeString()}.

; }

打开试试

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 s:
为了展示所有的组件都是孤立的,我们创建一个App组件来渲染三个组件:

function App() {
  return (
    
); } ReactDOM.render( , 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组件,反之亦然。

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/81906.html

相关文章

  • []React 的生命周期的使用场景

    摘要:译的生命周期的使用场景原文链接作者翻译上名这个图片,就是组件的生命周期,从形成到销毁的过程。这并不意味着没有用。最常见的用例更新以响应或更改。是否可以调用总结在理想的世界中,我们不会使用生命周期方法。 [译]React 的生命周期的使用场景 showImg(https://segmentfault.com/img/bVLTCt?w=2000&h=800); 原文链接:React Lif...

    klinson 评论0 收藏0
  • Android-Lifecycle超能解析-生命周期的那些事儿

    摘要:将的生命周期函数对应成,生命周期改变,会造成改变,而变化将触发事件,从而被接收。与一样,都是通过注册来监听的生命周期回调,来给每个添加的。 版权声明:本文已授权微信公众号:Android必修课,转载请申明出处众所周知,Android凡是需要展示给用户看的,都包含着生命周期这个概念,例如Activity、Fragment、View等都与生命周期息息相关,在生命周期函数里,它们各自完成创...

    Keven 评论0 收藏0
  • Android-Lifecycle超能解析-生命周期的那些事儿

    摘要:将的生命周期函数对应成,生命周期改变,会造成改变,而变化将触发事件,从而被接收。与一样,都是通过注册来监听的生命周期回调,来给每个添加的。 版权声明:本文已授权微信公众号:Android必修课,转载请申明出处众所周知,Android凡是需要展示给用户看的,都包含着生命周期这个概念,例如Activity、Fragment、View等都与生命周期息息相关,在生命周期函数里,它们各自完成创...

    ralap 评论0 收藏0
  • Android Architecture Components Part3:Lifecycle

    摘要:代表生命事件,是由层分发过来的,这些事件与中的生命回调相匹配。代表当前追踪的组件所处的生命状态。内部通过来注册了生命周期状态。减少逻辑处理与不必要的异常发生。 showImg(https://segmentfault.com/img/bVbcpqU?w=800&h=367); 上期文章我们讲解了LiveData,知道它是一个可观察容器同时具备生命感知能力。那么它的生命感知能力又是如何实...

    denson 评论0 收藏0
  • Android lifecyle 源码解剖

    摘要:使用详解使用详解源码解剖源码解剖地址技术人,一位不羁的码农。在中,它默认为我们初始化,作为一个成员变量。在方法中,它会判断我们是否已经添加,没有的话,添加进去。说在前面 本次推出 Android Architecture Components 系列文章,目前写好了四篇,主要是关于 lifecycle,livedata 的使用和源码分析,其余的 Navigation, Paging libr...

    番茄西红柿 评论0 收藏0

发表评论

0条评论

dadong

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<