diff --git a/content/docs/state-and-lifecycle.md b/content/docs/state-and-lifecycle.md index c58efae616..76d9c5beab 100644 --- a/content/docs/state-and-lifecycle.md +++ b/content/docs/state-and-lifecycle.md @@ -1,6 +1,6 @@ --- id: state-and-lifecycle -title: State and Lifecycle +title: State & 生命周期 permalink: docs/state-and-lifecycle.html redirect_from: - "docs/interactivity-and-dynamic-uis.html" @@ -8,9 +8,9 @@ prev: components-and-props.html next: handling-events.html --- -This page introduces the concept of state and lifecycle in a React component. You can find a [detailed component API reference here](/docs/react-component.html). +本页面介绍了 React 组件中 state 和生命周期的概念。你可以查阅[详细的组件 API 参考文档](/docs/react-component.html)。 -Consider the ticking clock example from [one of the previous sections](/docs/rendering-elements.html#updating-the-rendered-element). In [Rendering Elements](/docs/rendering-elements.html#rendering-an-element-into-the-dom), we have only learned one way to update the UI. We call `ReactDOM.render()` to change the rendered output: +请参考[前一章节](/docs/rendering-elements.html#updating-the-rendered-element)中时钟的例子。在[元素渲染](/docs/rendering-elements.html#rendering-an-element-into-the-dom)章节中,我们只了解了一种更新 UI 界面的方法。通过调用 `ReactDOM.render()` 来修改我们想要渲染的元素: ```js{8-11} function tick() { @@ -29,11 +29,11 @@ function tick() { setInterval(tick, 1000); ``` -[**Try it on CodePen**](http://codepen.io/gaearon/pen/gwoJZk?editors=0010) +[**在 CodePen 上尝试**](http://codepen.io/gaearon/pen/gwoJZk?editors=0010) -In this section, we will learn how to make the `Clock` component truly reusable and encapsulated. It will set up its own timer and update itself every second. +在本章节中,我们将学习如何封装真正可复用的 `Clock` 组件。它将设置自己的计时器并每秒更新一次。 -We can start by encapsulating how the clock looks: +我们可以从封装时钟的外观开始: ```js{3-6,12} function Clock(props) { @@ -55,11 +55,11 @@ function tick() { setInterval(tick, 1000); ``` -[**Try it on CodePen**](http://codepen.io/gaearon/pen/dpdoYR?editors=0010) +[**在 CodePen 上尝试**](http://codepen.io/gaearon/pen/dpdoYR?editors=0010) -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` 组件自我更新: ```js{2} ReactDOM.render( @@ -68,25 +68,25 @@ ReactDOM.render( ); ``` -To implement this, we need to add "state" to the `Clock` component. +我们需要在 `Clock` 组件中添加 "state" 来实现这个功能。 -State is similar to props, but it is private and fully controlled by the component. +State 与 props 类似,但是 state 是私有的,并且完全受控于当前组件。 -We [mentioned before](/docs/components-and-props.html#functional-and-class-components) that components defined as classes have some additional features. Local state is exactly that: a feature available only to classes. +我们[之前提到](/docs/components-and-props.html#functional-and-class-components)过组件如果一个组件用 class 定义时,会包含一些额外的特性。State 是: 仅属于 class 组件的特性。 -## Converting a Function to a Class +## 将函数组件转换成 class 组件 -You can convert a function component like `Clock` to a class in five steps: +通过以下五步将 `Clock` 的函数组件转成 class 组件: -1. Create an [ES6 class](https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Classes), with the same name, that extends `React.Component`. +1. 创建一个同名的 [ES6 class](https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Classes),并且继承于 `React.Component`。 -2. Add a single empty method to it called `render()`. +2. 添加一个空的 `render()` 方法。 + +3. 将函数体移动到 `render()` 方法之中。 -3. Move the body of the function into the `render()` method. +4. 在 `render()` 方法中使用 `this.props` 替换 `props`。 -4. Replace `props` with `this.props` in the `render()` body. - -5. Delete the remaining empty function declaration. +5. 删除剩余的空函数声明。 ```js class Clock extends React.Component { @@ -101,17 +101,17 @@ class Clock extends React.Component { } ``` -[**Try it on CodePen**](http://codepen.io/gaearon/pen/zKRGpo?editors=0010) +[**在 CodePen 上尝试**](http://codepen.io/gaearon/pen/zKRGpo?editors=0010) -`Clock` is now defined as a class rather than a function. +现在 `Clock` 组件被定义为 class,而不是函数。 -The `render` method will be called each time an update happens, but as long as we render `` into the same DOM node, only a single instance of the `Clock` class will be used. This lets us use additional features such as local state and lifecycle methods. +每次组件更新时 `render` 方法都会被调用,但只要在相同的 DOM 节点中渲染 `` ,就仅有一个 `Clock` 组件的 class 实例被创建使用。这就使得我们可以使用如 state 或生命周期方法等很多其他特性。 -## Adding Local State to a Class +## 向 class 组件中添加局部的 state -We will move the `date` from props to state in three steps: +我们通过以下三步将 `date` 从 props 移动到 state 中: -1) Replace `this.props.date` with `this.state.date` in the `render()` method: +1) 把 `render()` 方法中的 `this.props.date` 替换成 `this.state.date` : ```js{6} class Clock extends React.Component { @@ -126,7 +126,7 @@ class Clock extends React.Component { } ``` -2) Add a [class constructor](https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Classes#Constructor) that assigns the initial `this.state`: +2) 添加一个 [class 构造函数](https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Classes#Constructor),然后在该函数中为 `this.state` 赋初值: ```js{4} class Clock extends React.Component { @@ -146,7 +146,7 @@ class Clock extends React.Component { } ``` -Note how we pass `props` to the base constructor: +通过以下方式将 `props` 传递到父类的构造函数中: ```js{2} constructor(props) { @@ -155,9 +155,9 @@ Note how we pass `props` to the base constructor: } ``` -Class components should always call the base constructor with `props`. +Class 组件应该始终使用 `props` 参数来调用父类的构造函数。 -3) Remove the `date` prop from the `` element: +3) 移除 `` 元素中的 `date` 属性: ```js{2} ReactDOM.render( @@ -166,9 +166,9 @@ ReactDOM.render( ); ``` -We will later add the timer code back to the component itself. +我们之后会将计时器相关的代码添加到组件中。 -The result looks like this: +代码如下: ```js{2-5,11,18} class Clock extends React.Component { @@ -193,19 +193,19 @@ ReactDOM.render( ); ``` -[**Try it on CodePen**](http://codepen.io/gaearon/pen/KgQpJd?editors=0010) +[**在 CodePen 上尝试**](http://codepen.io/gaearon/pen/KgQpJd?editors=0010) -Next, we'll make the `Clock` set up its own timer and update itself every second. +接下来,我们会设置 `Clock` 的计时器并每秒更新它。 -## Adding Lifecycle Methods to a Class +## 将生命周期方法添加到 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](https://developer.mozilla.org/en-US/docs/Web/API/WindowTimers/setInterval) whenever the `Clock` is rendered to the DOM for the first time. This is called "mounting" in React. +当 `Clock` 组件第一次被渲染到 DOM 中的时候,就为其[设置一个计时器](https://developer.mozilla.org/en-US/docs/Web/API/WindowTimers/setInterval)。这在 React 中被称为“挂载(mount)”。 -We also want to [clear that timer](https://developer.mozilla.org/en-US/docs/Web/API/WindowTimers/clearInterval) whenever the DOM produced by the `Clock` is removed. This is called "unmounting" in React. +同时,当 DOM 中 `Clock` 组件被删除的时候,应该[清除计时器](https://developer.mozilla.org/en-US/docs/Web/API/WindowTimers/clearInterval)。这在 React 中被称为“卸载(umount)”。 -We can declare special methods on the component class to run some code when a component mounts and unmounts: +我们可以为 class 组件声明一些特殊的方法,当组件挂载或卸载时就会去执行这些方法: ```js{7-9,11-13} class Clock extends React.Component { @@ -233,9 +233,9 @@ class Clock extends React.Component { } ``` -These methods are called "lifecycle methods". +这些方法叫做“生命周期方法”。 -The `componentDidMount()` method runs after the component output has been rendered to the DOM. This is a good place to set up a timer: +`componentDidMount()` 方法会在组件已经被渲染到 DOM 中后运行,所以,最好在这里设置计时器: ```js{2-5} componentDidMount() { @@ -246,11 +246,11 @@ The `componentDidMount()` method runs after the component output has been render } ``` -Note how we save the timer ID right on `this`. +接下来把计时器的 ID 保存在 `this` 之中。 -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 doesn’t participate in the data flow (like a timer ID). +尽管 `this.props` 和 `this.state` 是 React 本身设置的,且都拥有特殊的含义,但是其实你可以向 class 中随意添加不参与数据流(比如计时器 ID)的额外字段。 -We will tear down the timer in the `componentWillUnmount()` lifecycle method: +我们会在 `componentWillUnmount()` 生命周期方法中清除计时器: ```js{2} componentWillUnmount() { @@ -258,9 +258,9 @@ We will tear down the timer in the `componentWillUnmount()` lifecycle method: } ``` -Finally, we will implement a method called `tick()` that the `Clock` component will run every second. +最后,我们会实现一个叫 `tick()` 的方法,`Clock` 组件每秒都会调用它。 -It will use `this.setState()` to schedule updates to the component local state: +使用 `this.setState()` 来时刻更新组件 state: ```js{18-22} class Clock extends React.Component { @@ -302,51 +302,51 @@ ReactDOM.render( ); ``` -[**Try it on CodePen**](http://codepen.io/gaearon/pen/amqdNA?editors=0010) +[**在 CodePen 上尝试**](http://codepen.io/gaearon/pen/amqdNA?editors=0010) -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. Since `Clock` needs to display the current time, it initializes `this.state` with an object including the current time. We will later update this state. +1) 当 `` 被传给 `ReactDOM.render()`的时候,React 会调用 `Clock` 组件的构造函数。 因为 `Clock` 需要显示当前的时间,所以它会用一个包含当前时间的对象来初始化 `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 then updates the DOM to match the `Clock`'s render output. +2) 之后 React 会调用组件的 `render()` 方法。这就是 React 确定该在页面上展示什么的方式。然后 React 更新 DOM 来匹配 `Clock` 渲染的输出。 -3) When the `Clock` output is inserted in the DOM, React calls the `componentDidMount()` lifecycle method. Inside it, the `Clock` component asks the browser to set up a timer to call the component's `tick()` method once a second. +3) 当 `Clock` 的输出被插入到 DOM 中后, React 就会调用 `ComponentDidMount()` 生命周期方法。在这个方法中,`Clock` 组件向浏览器请求设置一个计时器来每秒调用一次组件的 `tick()` 方法。 -4) Every second the browser calls the `tick()` method. Inside it, the `Clock` component schedules a UI update by calling `setState()` with an object containing the current time. Thanks to the `setState()` call, React knows the state has changed, and calls the `render()` method again to learn what should be on the screen. This time, `this.state.date` in the `render()` method will be different, and so the render output will include the updated time. React updates the DOM accordingly. +4) 浏览器每秒都会调用一次 `tick()` 方法。 在这方法之中,`Clock` 组件会通过调用 `setState()` 来计划进行一次 UI 更新。得益于 `setState()` 的调用,React 能够知道 state 已经改变了,然后会重新调用 `render()` 方法来确定页面上该显示什么。这一次,`render()` 方法中的 `this.state.date` 就不一样了,如此以来就会渲染输出更新过的时间。React 也会相应的更新 DOM。 -5) If the `Clock` component is ever removed from the DOM, React calls the `componentWillUnmount()` lifecycle method so the timer is stopped. +5) 一旦 `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: +例如,此代码不会重新渲染组件: ```js // Wrong this.state.comment = 'Hello'; ``` -Instead, use `setState()`: +而是应该使用 `setState()`: ```js // Correct this.setState({comment: 'Hello'}); ``` -The only place where you can assign `this.state` is the constructor. +构造函数是唯一可以给 `this.state` 赋值的地方: -### 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.props` 和 `this.state` 可能会异步更新,所以你不要依赖他们的值来更新下一个状态。 -For example, this code may fail to update the counter: +例如,此代码可能会无法更新计数器: ```js // Wrong @@ -355,7 +355,7 @@ this.setState({ }); ``` -To fix it, use a second form of `setState()` that accepts a function rather than an object. 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: +要解决这个问题,可以让 `setState()` 接收一个函数而不是一个对象。这个函数用上一个 state 作为第一个参数,将此次更新被应用时的 props 做为第二个参数: ```js // Correct @@ -364,7 +364,7 @@ this.setState((state, props) => ({ })); ``` -We used an [arrow function](https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Functions/Arrow_functions) above, but it also works with regular functions: +上面使用了[箭头函数](https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Functions/Arrow_function),不过使用普通的函数也同样可以: ```js // Correct @@ -375,11 +375,11 @@ this.setState(function(state, props) { }); ``` -### 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 包含几个独立的变量: ```js{4,5} constructor(props) { @@ -391,7 +391,7 @@ For example, your state may contain several independent variables: } ``` -Then you can update them independently with separate `setState()` calls: +然后你可以分别调用 `setState()` 来单独地更新它们: ```js{4,10} componentDidMount() { @@ -409,27 +409,27 @@ Then you can update them independently with separate `setState()` calls: } ``` -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. +不管是父组件或是子组件都无法知道某个组件是有状态的还是无状态的,并且它们也并不关心它是函数组件还是 class 组件。 -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 为局部的或是封装的的原因。除了拥有并设置了它的组件,其他组件都无法访问。 -A component may choose to pass its state down as props to its child components: +组件可以选择把它的 state 作为 props 向下传递到它的子组件中: ```js

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

``` -This also works for user-defined components: +这对于自定义组件同样适用: ```js ``` -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` 组件会在其 props 中接收参数 `date`,但是组件本身无法知道它是来自于 `Clock` 的 state,或是 `Clock` 的 props,还是手动输入的: ```js function FormattedDate(props) { @@ -437,13 +437,13 @@ function FormattedDate(props) { } ``` -[**Try it on CodePen**](http://codepen.io/gaearon/pen/zKRqNB?editors=0010) +[**在 CodePen 上尝试**](http://codepen.io/gaearon/pen/zKRqNB?editors=0010) -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 总是所属于特定的组件,而且从该 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: +为了证明每个组件都是真正独立的,我们可以创建一个渲染三个 `Clock` 的 `App` 组件: ```js{4-6} function App() { @@ -462,8 +462,8 @@ ReactDOM.render( ); ``` -[**Try it on CodePen**](http://codepen.io/gaearon/pen/vXdGmd?editors=0010) +[**在 CodePen 上尝试**](http://codepen.io/gaearon/pen/vXdGmd?editors=0010) -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. You can use stateless components inside stateful components, and vice versa. +在 React 应用中,组件是有状态组件还是无状态组件属于组件实现的细节,它可能会随着时间的推移而改变。你可以在有状态的组件中使用无状态的组件,反之亦然。