w3ctech

React 初学者教程 11:组件的生命周期

概述:学习生命周期方法,从而更好地理解组件能做和不能做什么。

在开始,我们以一个很简单的视图组件以及他们要做什么开始。随着我们对 React 更多,做了更酷以及更复杂的事情,结果发现组件并非那么简单。它们帮助处理属性、状态、事件,并且经常负责其它组件的幸福。跟踪组件做的所有事情有时可能很难。

为帮助做这些事情,React 给我们提供了一些生命周期方法。生命周期方法是组件正常运转时自动调用的特殊方法。它们告知我们组件生命中重要的里程碑,我们可以用这些通知来只是注意,或者改变组件要做的事情。

本教程中,我们将要看看这些生命周期方法,并学习我们能用它们做什么。

初识生命周期方法

生命周期方法不是很复杂。我们可以把它们当作是在组件生命中的不同的点被调用的美化的事件处理器,并且就像事件处理器一样,我们可以在这些不同的点编写代码做一些事情。在深入之前,我们先来快速了解一下生命周期方法。它们是 componentWillMount, componentDidMount, componentWillUnmount, componentWillUpdate, componentDidUpdate, shouldComponentUpdate, componentWillReceiveProps。 还有三个方法严格上讲并非生命周期方法,但是我们仍要把它们跟生命周期方法混在一起,它们是 getInitialState、getDefaultProps 和 render。

这些方法中,有些名称可能看起来是熟悉,有些可能是第一次看到。不要着急。在本教程结束后,你对所有这些方法都很熟悉。我们打算要做的是从不同角度看看这些生命周期方法。我们还是以代码开始!

看看生命周期方法起作用

学习这些生命周期方法与记住你没有计划去的陌生地方一样令人激动。为了让这一切变得更舒服,我打算首先通过一个简单的示例来玩玩。

到这个地址, 当页面加载时,你会看到一个以前计数器示例的变种:

先不要点击按钮或者任何东西。如果已经点击了按钮,那就重新刷新一下页面,让示例重新开始。

现在打开浏览器的开发功能根据,看看 Console 标签。在 Chrome 中,我们会看到如下的东西:

注意一下打印的东西。你会看到一些消息,这些消息的开头看起来像生命周期方法的名字。如果现在你点击加号按钮,会看到 Console 会显示更多被调用的生命周期方法:

玩这个示例一会儿。这个示例所做的是,允许你把所有这些生命周期方法放在我们前面已经看到的组件上下文中。随着你继续点击加号按钮,更多的生命周期方法条目就会打印出来。最后,当计数器到了 5 时,示例消失,控制台输出如下条目:componentWillUnmout: Component is about to be removed from the DOM!。 此时,示例结束。

现在你已经看过示例,我们来看看负责所有这些东西的组件:

var CounterParent = React.createClass({
  getDefaultProps: function(){
    console.log("getDefaultProps: Default prop time!");
    return {};
  },
  getInitialState: function() {
    console.log("getInitialState: Default state time!");
    return {
      count: 0
    };
  },
  increase: function() {
    this.setState({
      count: this.state.count + 1
    });
  },
  componentWillUpdate: function(newProps, newState) {
      console.log("componentWillUpdate: Component is about to update!");
  },
  componentDidUpdate: function(currentProps, currentState) {
      console.log("componentDidUpdate: Component just updated!");
  },
  componentWillMount: function() {
      console.log("componentWillMount: Component is about to mount!");
  },
  componentDidMount: function() {
      console.log("componentDidMount: Component just mounted!");
  },
  componentWillUnmount: function() {
      console.log("componentWillUnmount: Component is about to be removed from the DOM!");
  },
  shouldComponentUpdate: function(newProps, newState) {
    console.log("shouldComponentUpdate: Should component update?");

    if (newState.count < 5) {
      console.log("shouldComponentUpdate: Component should update!");
      return true;
    } else {
      ReactDOM.unmountComponentAtNode(destination);
      console.log("shouldComponentUpdate: Component should not update!");
      return false;
    }
  },
  componentWillReceiveProps: function(newProps){
    console.log("componentWillReceiveProps: Component will get new props!");
  },
  render: function() {
      var backgroundStyle = {
        padding: 50,
        border: "#333 2px dotted",
        width: 250,
        height: 100,
        borderRadius: 10,
        textAlign: "center"
      };

      return (
        <div style={backgroundStyle}>
          <Counter display={this.state.count}/>
          <button onClick={this.increase}>
            +
          </button>
        </div>
      );
    }
});

我们花点时间理解一下这段代码做什么。这段代码看起来有点长,但是只是列出定义有 console.log 语句的每个生命周期方法。看完代码后,多玩几次。相信我,你在这个示例上花的时间越多,思考发生了什么,就会觉得越有意思。下面的小节我们会看每个生命周期方法中的渲染、更新和卸载阶段,这是相当枯燥的。不要说我没有提醒你。

初始渲染阶段

当组件准备开始其生命,进入 DOM 时,如下的生命周期方法被调用:

当示例被加载时,你在控制台看到的,就是这里看到的无彩色的版本。现在我们继续深入学习每个生命周期方法:

  • getDefaultProps:该方法允许我们指定 this.props 的默认值。它在组件被创建或者父组件的任何属性传递进来之前被调用。
  • getInitialState:本方法允许我们指定在组件被创建前 this.state的默认值。与 getDefaultProps 方法一样,它也是在组件被创建前被调用。
  • componentWillMount:这是组件被渲染到 DOM 之前被调用的最后一个方法。一个需要指出的重要事情是:如果在这个方法中调用 setState,那么组件是不会被重新渲染。
  • render:这个方法对于我们来说肯定很熟悉。每个组件必须定义有这个方法,它负责返回单个根 HTML 节点(该节点内部可以有很多字节点)。如果我们不想渲染任何东西,让它返回 null 或者 false 即可。
  • componentDidMount:组件渲染并且放到 DOM 后,该方法会立即被调用。在这个点上,我们可以安全的执行任何 DOM 查询操作,而不用担心组件是否被创建。如果有代码依赖于组件是否准备好了,那么你也可以在这里指定所有代码。

除了 render 方法外,所有这些生命周期方法只能触发一次。这与我们下面要看到的方法有很大不同。

更新阶段

在组件添加到 DOM 之后,当属性或者状态发生更改时,组件可能会更新。在此期间,会有一些生命周期方法被调用。

处理状态改变

首先,我们来看看状态改变。当状态改变发生时,前面我们提到组件会再次调用其 render 方法。任何依赖于该组件的输出的组件的 render 方法也会被调用。这样做就可以确保组件总是显示最新版本的自己。这一切都是真的,但是这只是对发生的事情的部分表示。

当状态发生改变时,如下生命周期方法被调用:

这些生命周期方法要做的事情如下:

shouldComponentUpdate 有时,当一个状态发生改变时,你不想让组件更新。这个方法可以让我们控制更新行为。如果你使用该方法,并返回一个 true 值,组件就会被更新。如果返回一个 false 值,该组件就不会更新。

如下是一个简单的示例:

shouldComponentUpdate: function(newProps, newState) {
  if (newState.id <= 2) {
    console.log("Component should update!");
    return true;
  } else {
    console.log("Component should not update!");
    return false;
  }
}

该方法带有两个参数:newProps 和 newState。上面的代码片段用来判断 id 状态属性的新值是否小于等于 2。如果是,那么返回 true,指示该组件要更新。如果不是,那么返回 false,指示组件不更新。

componentWillUpdate 该方法在组件将要被更新之前被调用。这里没啥值得兴奋的。有一件事情要指出的是,不能在这个方法中通过调用 this.setState 来修改状态。

render 如果没有通过 shouldComponentUpdate 忽略更新,那么 render 中的代码会再次被调用,以确保组件正确显示自己。

componentDidUpdate 该方法在组件更新以及 render 方法被调用过后被调用。如果你要在更新发生后执行一些代码,那么就应该把代码放在这个方法中。

处理 prop 改变

组件更新的另一个时间是,当组件已经被渲染到 DOM 以后,其 prop 值发生改变时。在这种情况下,如下的生命周期方法被调用:

这里唯一的新方法是 componentWillReceiveProps。该方法只返回一个参数,并且该参数包含将要赋值的新 prop 值。

剩下的生命周期方法我们在前面查看状态改变时已经看过了,所以这里就不在重复了。在处理 prop 修改时,它们的行为是一致的。

卸载阶段

最后一个阶段是当组件要销毁,并从 DOM 中删除时:

这里唯一的生命周期方法是 componentWillUnmount。我们可以在这个方法中执行清理相关的任务,比如移除事件监听器、停止计数器等等。在该方法被调用后,组件就从 DOM 中移除,你可以对它说拜拜了。

总结

组件是迷人的小东西。表面上看它们并没有什么。就像一部好的海洋纪录片一样,当我们稍微认真点看的话,就像看到一个完全不同的世界。事实证明,React 不断地在每次有兴趣的事情发生时候监视和通知组件。这都是通过生命周期方法实现的。现在,我想安慰你的是,知道每个生命周期方法做什么以及什么时候它被调用,是总有一天会派上用场的。你所学的一切并非仅是繁琐的知识,如果你能凭记忆描述所有生命周期方法,你的朋友们会被打动的。

w3ctech微信

扫码关注w3ctech微信公众号

共收到0条回复