[译]React生命周期方法

原文地址:React Lifecycle Methods- how and when to use them
作者: Scott Domes

上面的图描绘了一个React组件的一生,从生(pre-mounting)到死(unmounting)。

React的美好之处在于她把复杂的UI颗粒化。这样我们不仅可以分割应用,并且可以按需求自定义分割的每一部分。

通过使用生命周期方法,我们可以控制UI渲染、更新的每一个小阶段,考虑如何重新渲染,以及最终的展示效果。

好了,快上车。

componentWillMount

你的组件将很快的展示在屏幕上。写着JSX的render函数将要被调用。你想做什么?

答案是...也许什么也没有。抱歉开始的有些慢,但是componentWillMount有点不太中用。

关于componentWillMount的事情是现在还没有可以用的组件,所以你没法在此时处理DOM。

同时,在初始组件配置的constructor函数调用后,还没有东西发生改变。


(使用constructor设置默认状态)

此刻你的组件还在默认的状态下。几乎所有的东西都需要其余的组件代码来处理,而不是额外的生命周期函数。

例外的是这里可以写任何只能在运行时进行的配置 — 例如,链接外部API。比如,如果你在应用中使用Firebase,就需要在第一次构建的时候进行设置。

但关键问题是,类似这样的配置应该写在更高级别的组件中(根组件)。那意味着99%的组件可能都用不到componentWillMount方法。

你可能见到过有的人在componentWillMount中使用AJAX获取组件的数据。不要这样做。我们会在之后的生命周期中处理这样的事件。

常见用例: root组件中的应用设置。
可以使用setState: 不,用默认state代替。

componentDidMount

我们接着说。现在你的组件已经创建好并等着被使用。然后呢?

这里是你加载数据的地方。引用Tyler McGinnis的话来解释

你无法确定AJAX请求不会在组件构建完成之前返回数据,如果它做到了,那就意味着你在一个还没构建完成的组件中尝试使用setState,这么做不但不会起效,React也不希望你这么做。在componentDidMount中则可以保证这里已经有组件可以用来更新。

你可以在这里获得更多的相关内容React Interview Questions

componentDidMount中也可以做一些没有组件时无法办到的有趣的事情。例如:

  • 画一个<canvas>元素
  • 初始化一个Masonry布局
  • 添加事件监听函数

基本上,你可以在这里做所有需要有DOM才能进行的设置,并且开始获取所有需要的数据。

常见用例: 使用AJAX获取组件数据。
可以使用setState: 当然。

componentWillReceiveProps

我们的组件运行的一切正常,直到一些突然到来的新props打乱了这一切。

也许是一些由父组件在componentDidMount中加载的数据向下传递了进来。

在我们的组件对这些新的props做任何事情之前,componentWillReceiveProps会被调用,并把新的props作为参数传递。

有趣的是,在这里我们既可以获得新的props(通过nextProps参数),也可以得到当前的props(通过this.props)。

我们应该做的是:

  1. 检查哪些props将要改变(警告 — 有的时候没有任何变化也会调用componentWillReceiveProps;React只想做一些检查)
  2. 如果props要做重大的改变,那就执行。

举个栗子。像上面提到的那样,我们有一个canvas元素。我们要基于this.props.percent在上面画一个圆形图表。


(看起来不错)

当我们接收到新的props的时候,如果百分比发生了变化,我们希望重新画这个图形。这里是代码:

还有一个警告是 — componentWillReceiveProps不会在初始渲染中调用。我的意思是严格的讲组件接收props,但是没有任何老的props可以拿来对比,所以…这不算数。

常见用例: 对个别props的改变触发state的改变。
可以使用setState: 可以。

shouldComponentUpdate

现在我们的组件开始变得有些不安。

我们有了新的props。React文档上讲当一个组件收到了新的props,或者新的state的时候,它将会更新。

但是我们的组件有一些小焦虑,并且想在这之前先得到许可。

这就是我们得到的 — 一个shouldComponentUpdate方法,方法有两个参数:nextProps和nextState。

shouldComponentUpdate方法返回一个布尔值 — 用以回答组件“我可以重绘么?”的问题。默认情况下通常是返回true(去吧皮卡丘)。

但是如果你担心多余的渲染,shouldComponentUpdate也是一个可以用来提升性能的地方。

这里是我写的一篇关于用shouldComponentUpdate解决类似问题的的文章 How to Benchmark React Components: The Quick and Dirty Guide

在这篇文章中,我们谈论一个有很多字段的表格。问题是每当这个表格重绘的时候,每个字段都会重新渲染,让过程变得很慢。

常见用例: 管理组件是否重新渲染。
可以使用setState: 不。

componentWillUpdate

现在我们已经允许了组件更新。“需要我在重新渲染前做一些什么吗?”我们的组件问到。"不需要"。别再来打扰我们了。

在MuseFind的所有代码库中,我们从来没有用过componentWillUpdate。功能上讲,它和componentWillReceiveProps类似,除非你不允许调用this.setState。

如果你使用shouldComponentUpdate并且需要在props改变时候做一些处理,componentWillUpdate会有意义。但是它可能不会给你更多的实用价值。

常见用例: 在一个有shouldComponentUpdate方法的组件上代替componentWillReceiveProps使用。
可以使用setState: 否。

componentDidUpdate

干的漂亮,小组件。

在这里我们可以做类似在componentDidMount里做的事情 — 重新设置masonry布局,重新绘制我们的cavans,等等。

等等,难道我们不是在componentWillReceiveProps中重绘了画布么?

是的。原因是:在componentDidUpdate,你并不知道它为啥子更新。

所以如果我们的组件接收了和canvas无关的props,我们并不想在它每次更新的时候花时间来渲染画布。

这并不意味着componentDidUpdate就没有用。回到我们masonry的栗子中,我们想在DOM更新之后改变网格,所以我们使用componentDidUpdate来实现。

常见用例: 响应prop或state的改变来更新DOM。
可以使用setState: 是的。

componentWillUnmount

几乎要结束了。

你的组件可能要永远的离开了,真让人伤心。

在它走之前问道,还有什么最后的需求么。

这里你可以取消任何发出的网络请求,或者移除组件中所有的事件绑定。

大致上讲,清理所有会引起组件问题的东西 — 既然走就让它走的彻底一些。

常见用例: 清理组件遗留的东西。
可以使用setState: 都要走了还用什么setState。

总结

在理想情况下,我们不使用声明周期函数。我们所有渲染的问题都通过state和props控制。

但这并不是理想中的世界,有的时候还是需要一些对组件更新的控制。

小心谨慎并尽可能少的使用它们。希望这篇文章能帮助你对何时以及怎样使用生命周期方法有一些启发。

Comments
Write a Comment