React PureComponent 源码剖析

TL;DR

React 15.3.0 新增了一个 PureComponent 类,以 ES2015 class 的体式格局轻易地定义纯组件 (pure component)。这篇文章剖析了一下源码完成,并衍生探讨了下 shallowComparePureRenderMixin。相干的 GitHub PR 在 这里

PureComponent 源码剖析

这个类的用法很简单,假如你有些组件是纯组件,那末把继续类从 Component 换成 PureComponent 即可。当组件更新时,假如组件的 propsstate 都没发作转变,render 要领就不会触发,省去 Virtual DOM 的天生和比对历程,到达提拔机能的目标。

import React, { PureComponent } from 'react'

class Example extends PureComponent {
  render() {
    // ...
  }
}

PureComponent 本身的源码也很简单,节选以下:

function ReactPureComponent(props, context, updater) {
  // Duplicated from ReactComponent.
  this.props = props;
  this.context = context;
  this.refs = emptyObject;
  // We initialize the default updater but the real one gets injected by the
  // renderer.
  this.updater = updater || ReactNoopUpdateQueue;
}

function ComponentDummy() {}
ComponentDummy.prototype = ReactComponent.prototype;
ReactPureComponent.prototype = new ComponentDummy();
ReactPureComponent.prototype.constructor = ReactPureComponent;
// Avoid an extra prototype jump for these methods.
Object.assign(ReactPureComponent.prototype, ReactComponent.prototype);
ReactPureComponent.prototype.isPureReactComponent = true;

上面的 ReactPureComponent 就是暴露给外部运用的 PureComponent 。能够看到它只是继续了 ReactComponent 再设定了一下 isPureReactComponent 属性。ComponentDummy 是典范的 JavaScript 原型模仿继续的做法,对此有迷惑的能够看 我的另一篇文章 。别的,为了防止原型链拉长致使要领查找的机能开支,还用 Object.assign 把要领从 ReactComponent 拷贝过来了。

PureRenderMixin 不一样的是,这里完整没有完成 shouldComponentUpdate。那 PureComponent 的 props/state 比对是在那里做的呢?答案是 ReactCompositeComponent

ReactCompositeComponent 这个类的信息太少,我只能推想它是担任现实衬着并保护组件实例的对象。发起人人从高条理相识 React 对组件的更新机制即可。以下几篇官方文档看完就足够了。

这个类的代码修改许多,但症结就在 这里 。下面是我简化后的代码片断:

// 定义 CompositeTypes
var CompositeTypes = {
  ImpureClass: 0,         // 继续自 Component 的组件
  PureClass: 1,           // 继续自 PureComponent 的组件
  StatelessFunctional: 2, // 函数组件
};

// 省略一堆代码,由于加入了 CompositeTypes 形成的调解

// 这个变量用来掌握组件是不是须要更新
var shouldUpdate = true;

// inst 是组件实例
if (inst.shouldComponentUpdate) {
  shouldUpdate = inst.shouldComponentUpdate(nextProps, nextState, nextContext);
} else {
  if (this._compositeType === CompositeType.PureClass) {
    // 用 shallowEqual 对照 props 和 state 的修改
    // 假如都没转变就不必更新
    shouldUpdate =
      !shallowEqual(prevProps, nextProps) ||
      !shallowEqual(inst.state, nextState);
  }
}

简而言之,ReactCompositeComponent 会在 mount 的时刻推断各个组件的范例,设定 _compositeType ,然后依据这个范例来推断是非须要更新组件。这个 PR 中大部份修改都是 由于加了 CompositeTypes 而做的调解性事变,现实跟 PureComponent 有关的就是 shallowEqual 的那两行。

关于 PureComponent 的源码剖析就到这里。其他的就都是细节和测试,有兴致的能够本身看看 PR 。

shallowEqual, shallowCompare, PureRenderMixin 的联络

我们晓得在 PureComponent 涌现之前,shallowComparePureRenderMixin 都能够做一样的事变。因而猎奇看了一下后二者的代码。

shallowCompare 的源码:

var shallowEqual = require('shallowEqual');

function shallowCompare(instance, nextProps, nextState) {
  return (
    !shallowEqual(instance.props, nextProps) ||
    !shallowEqual(instance.state, nextState)
  );
}

module.exports = shallowCompare;

PureRenderMixin 的源码:

var shallowCompare = require('shallowCompare');

var ReactComponentWithPureRenderMixin = {
  shouldComponentUpdate: function(nextProps, nextState) {
    return shallowCompare(this, nextProps, nextState);
  },
};

module.exports = ReactComponentWithPureRenderMixin;

能够看到,shallowCompare 依靠 shallowEqual ,做的是跟刚才在 ReactCompositeComponent 里一样的事变 — 对照 props 和 state 。这个东西函数平常合营组件的 shouldComponentUpdate 一同运用,而这就是 PureRenderMixin 做的事变。不过 PureRenderMixin 是合营 React.createClass 这类老的组件定义体式格局运用的,在 ES2015 class 里用起来不是很轻易,这也是 PureComponent 降生的缘由之一。

末了 shallowEqual 这玩意定义在那里呢?它实在不是 React 的一部份,而是 fbjs 的一部份。这是 Facebook 内部运用的一个东西集。

小结

React 之前一向没有针对 ES2015 class 的纯组件写法,虽然本身完成起来并不贫苦,但这也算给出了一个官方的解决方案,能够不再依靠 addon 了。不过 PureComponent 也不是全能的,特定情况下本身完成 shouldComponentUpdate 能够更高效。

参考资料

PureComponent PR
shallowEqual
Shallow Compare
PureRenderMixin

    原文作者:darkbaby123
    原文地址: https://segmentfault.com/a/1190000006741060
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞