TL;DR
React 15.3.0 新增了一个 PureComponent
类,以 ES2015 class 的体式格局轻易地定义纯组件 (pure component)。这篇文章剖析了一下源码完成,并衍生探讨了下 shallowCompare
和 PureRenderMixin
。相干的 GitHub PR 在 这里 。
PureComponent 源码剖析
这个类的用法很简单,假如你有些组件是纯组件,那末把继续类从 Component
换成 PureComponent
即可。当组件更新时,假如组件的 props
和 state
都没发作转变,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
涌现之前,shallowCompare
和 PureRenderMixin
都能够做一样的事变。因而猎奇看了一下后二者的代码。
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
能够更高效。