为什么React16要更改组件的生命周期(上)

  作为一个专业的 React开发者,我们必须要求自己在知其然的基础上,知其所以然。从“What to do”到“How to do”,再到“Why to do”。以 React 的基本原理为引子,对 React 15、React 16 两个版本的生命周期进行探讨、比对和总结,通过搞清楚一个又一个的“Why”,建立系统而完善的生命周期知识体系

生命周期背后的设计思想:把握 React 中的“大方向”

  如果经常翻阅 React官网或者 React官方的一些文章,会发现“组件”和“虚拟 DOM”这两个词的出镜率是非常高的,它们是 React基本原理中极为关键的两个概念。

虚拟 DOM:核心算法的基石

  虚拟 DOM在整个 React工作流中的作用:

  1. 组件在初始化时,会通过调用生命周期中的 render方法,生成虚拟 DOM,然后再通过调用 ReactDOM.render 方法,实现虚拟 DOM到真实 DOM 的转换。
  2. 当组件更新时,会再次通过调用 render方法生成新的虚拟 DOM,然后借助 diff(这是一个非常关键的算法)定位出两次虚拟 DOM 的差异,从而针对发生变化的真实 DOM 作定向更新。

组件化:工程化思想在框架中的落地

  在一个 React项目中,几乎所有的可见/不可见的内容都可以被抽离为各种各样的组件,每个组件既是“封闭”的,也是“开放”的。

  • 封闭:主要是针对“渲染工作流”(指从组件数据改变组件实际更新发生的过程)来说的。在组件自身的渲染工作流中,每个组件都只处理它内部的渲染逻辑。在没有数据流交互的情况下,组件与组件之间可以做到“各自为政”。
  • 开放:针对组件间通信来说的。React 允许开发者基于“单向数据流”的原则完成组件间的通信。而组件之间的通信又将改变通信双方/某一方内部的数据,进而对渲染结果构成影响。所以说在数据这个“红娘”的牵线搭桥之下,组件之间又是彼此开放的,是可以相互影响的。

生命周期方法的本质:组件的“灵魂”与“躯干”

  倘若把虚拟 DOM、组件化这两块知识整合一下,就会发现这两个概念似乎都在围着 render这个生命周期打转:虚拟 DOM 自然不必多说,它的生成都要仰仗 render;而组件化概念中所提及的“渲染工作流”,这里指的是从组件数据改变组件实际更新发生的过程,这个过程的实现同样离不开 render

  由此看来,render方法在整个组件生命周期中确实举足轻重,它担得起“灵魂”这个有分量的比喻。那么如果将 render方法比作组件的“灵魂”,render之外的生命周期方法就完全可以理解为是组件的“躯干”。

拆解 React 生命周期:从 React 15 说起

  在 React 15 中,需要关注以下几个生命周期方法:

constructor()
componentWillReceiveProps()
shouldComponentUpdate()
componentWillMount()
componentWillUpdate()
componentDidUpdate()
componentDidMount()
render()
componentWillUnmount()

  这些生命周期方法是如何彼此串联、相互依存的呢?

在这里插入图片描述

Mounting 阶段:组件的初始化渲染(挂载)

  挂载过程在组件的一生中仅会发生一次,在这个过程中,组件被初始化,然后会被渲染到真实 DOM里,完成所谓的“首次渲染”。

  在挂载阶段,一个 React组件会按照顺序经历如下图所示的生命周期:

在这里插入图片描述

  首先来看 constructor方法,该方法仅仅在挂载的时候被调用一次,我们可以在该方法中对 this.state 进行初始化:

constructor(props) {
  console.log("进入constructor");
  super(props);
  // state 可以在 constructor 里初始化
  this.state = { text: "子组件的文本" };
}

  componentWillMountcomponentDidMount方法同样只会在挂载阶段被调用一次。其中 componentWillMount会在执行 render方法前被触发,一些开发者习惯在这个方法里做一些初始化的操作,但这些操作往往会伴随一些风险或者说不必要性。

  接下来 render方法被触发。注意 render在执行过程中并不会去操作真实 DOM(也就是说不会渲染),它的职能是把需要渲染的内容返回出来。真实 DOM 的渲染工作,在挂载阶段是由 ReactDOM.render来承接的

  componentDidMount 方法在渲染结束后被触发,此时因为真实 DOM 已经挂载到了页面上,我们可以在这个生命周期里执行真实 DOM 相关的操作。此外,类似于异步请求、数据初始化这样的操作也大可以放在这个生命周期来做

Updating 阶段:组件的更新

  组件的更新分为两种:一种是由父组件更新触发的更新;另一种是组件自身调用自己的 setState触发的更新。这两种更新对应的生命周期流程如下图所示:

在这里插入图片描述

componentWillReceiProps 到底是由什么触发的?

  从图中你可以明显看出,父组件触发的更新和组件自身的更新相比,多出了这样一个生命周期方法:

componentWillReceiveProps(nextProps)

  在这个生命周期方法里,nextProps表示的是接收到新 props内容,而现有的 props(相对于 nextProps的“旧 props”)我们可以通过this.props 拿到,由此便能够感知到 props的变化。

  componentReceiveProps 并不是由 props 的变化触发的,而是由父组件的更新触发的,这个结论,请你谨记。

组件自身 setState 触发的更新

  this.setState() 调用后导致的更新流程,前面大图中已经有体现

  先来说说 componentWillUpdatecomponentDidUpdate这一对好基友。componentWillUpdate会在 render前被触发,它和 componentWillMount类似,允许你在里面做一些不涉及真实 DOM 操作的准备工作;而 componentDidUpdate则在组件更新完毕后被触发,和 componentDidMount类似,这个生命周期也经常被用来处理 DOM操作。此外,我们也常常将 componentDidUpdate的执行作为子组件更新完毕的标志通知到父组件。

render 与性能:初识 shouldComponentUpdate

  这里需要重点提一下 shouldComponentUpdate这个生命周期方法,它的调用形式如下所示:

shouldComponentUpdate(nextProps, nextState)

  render 方法由于伴随着对虚拟 DOM 的构建和对比,过程可以说相当耗时。而在 React 当中,很多时候我们会不经意间就频繁地调用了 render。为了避免不必要的 render操作带来的性能开销,React 为我们提供了 shouldComponentUpdate这个口子。

  React 组件会根据 shouldComponentUpdate的返回值,来决定是否执行该方法之后的生命周期,进而决定是否对组件进行re-render(重渲染)。shouldComponentUpdate的默认值为 true,也就是说“无条件 re-render”。在实际的开发中,我们往往通过手动往 shouldComponentUpdate中填充判定逻辑,或者直接在项目中引入 PureComponent等最佳实践,来实现“有条件的 re-render”。

Unmounting 阶段:组件的卸载

  组件的销毁阶段本身是比较简单的,只涉及一个生命周期,如下图所示:

在这里插入图片描述

  这个生命周期本身不难理解,我们重点说说怎么触发它。组件销毁的常见原因有以下两个。

  • 组件在父组件中被移除了:这种情况相对比较直观,对应的就是我们上图描述的这个过程。
  • 组件中设置了 key属性,父组件在 render的过程中,发现 key值和上一次不一致,那么这个组件就会被干掉。
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值