[email protected]源码解读之基类ReactBaseClasses

「这是我参与11月更文挑战的第23天,活动详情查看:2021最后一次更文挑战

react对组件作了抽象,下面是react对组件的抽象。

/**
 * Copyright (c) Facebook
 * This source code is licensed under the MIT
 */
复制代码

可以看到,版权属于Facebook。采用MIT许可证。MIT许可证的含义为编写的软件可以闭源,但必须声明版权所属,同时可以以自己的名字发行广告。也就是说你可以使用它,并且还可以使用它编写的代码获取利润,并且可以闭源自己的软件代码。

function Component(props, context, updater) {
  this.props = props;
  this.context = context;
  this.refs = emptyObject;
  this.updater = updater || ReactNoopUpdateQueue;
}
复制代码

new 运算符创建一个用户定义的对象类型的实例或具有构造函数的内置对象的实例。(摘自MDN)

简单说,new运算符会创建一个实例。传送门

什么是实例? 这里我们用几个句子,让读者更直观地理解实例。

  • 你们哥俩好像一个模子里出来地。(你们有着相同的基因)
  • 用模具做出来的饼干。(做饼干的模具有相同的外形深度)

这里react作者采用函数的形式构造了一个伪类。 Component构造函数接收三个参数:

  • props,组件属性,也即jsx里给标签添加的属性。
  • context,上下文
  • updater,更新器,用来视图更新。

将Component首字母大写,表示这是一个类(伪类)。这个基础类的作用是帮助更新一个组件的状态。

Component.prototype.setState = function(partialState, callback) {
  if (
    typeof partialState !== 'object' &&
    typeof partialState !== 'function' &&
    partialState != null
  ) {
    throw new Error(
      'setState(...): takes an object of state variables to update or a ' +
        'function which returns an object of state variables.',
    );
  }

  this.updater.enqueueSetState(this, partialState, callback, 'setState');
};
复制代码

随后,react给这个伪类提供了一个setState方法,如果传递的部分状态不是对象或者一个函数就会抛出一个错误。这样限制了这个方法的参数类型。

然后通过更新队列代理变更状态更新视图的操作,因而,注释说,setState方法不保证状态更新的同步性。也就是说这个代理收到setState请求后,首先会将这个过程入队,在一定的时机批量更新。

所谓队列,就是先入先出,不过更新器会合并这一更新。我们可以给构造函数传递更新其,因而我们可以定制我们自己的更新策略。

Component.prototype.forceUpdate = function(callback) {
  this.updater.enqueueForceUpdate(this, callback, 'forceUpdate');
};
复制代码

继而react给Component这个伪类又添加了一个方法,也就是在原型对象上添加了一个属性。 forceUpdate同样也是借助更新器代理做这件事。 在这里,react相当于规定了两个接口,我们要实现更新器,必须实现enqueueSetStateenqueueForceUpdate这两个方法。 通过面向接口编程,我们可以不用考虑方法的具体实现,接口内部做了什么修改,对调用者来说是一个黑盒子。这样,我们可以不断优化代码而不必担心代码突然跑不起来。这就是约定的强大作用。不是有一种编码方式,约定大于配置

function ComponentDummy() {}
ComponentDummy.prototype = Component.prototype;
const pureComponentPrototype = (PureComponent.prototype = new ComponentDummy());
pureComponentPrototype.constructor = PureComponent;
Object.assign(pureComponentPrototype, Component.prototype);
pureComponentPrototype.isPureReactComponent = true;
复制代码
  1. PureComponent的构造函数和Component的构造函数一摸一样。
  2. 这里react声明了一个伪类ComponentDummy,同时将其原型赋值为Component的原型,这样,ComponentDummy就拥有了ComponentsetStateforceUpdate方法。这样实现了继承
  3. 然后将PureComponent的原型设置为ComponentDummy的实例。这样Component原型上props,context,updater(这些属性是实例属性)的变更不会影响到PureComponent,每一个实例的props,context,updater都是独立的,只受实例的影响,不会受到Component的影响。
  4. 通过设置是否纯组件,来变更组件比对状态的策略,采用浅比对来提升性能。
  5. 通过声明一个pureComponentPrototype常量来为PureComponent的显示原型的constructorisPureReactComponent属性赋值。

Object.assign()  方法用于将所有可枚举属性的值从一个或多个源对象分配到目标对象。它将返回目标对象。

这里目标对象是pureComponentPrototype也就是PureComponent的显式原型,这里再次合并原型对象,react说是为了避免这些方法的一个额外的原型跳跃(jump),因为PureComponent的原型被设置为了ComponentDummy的实例,这样继承的原型方法会通过原型链查找,造成一定的性能损失,通过调用Object.assign,避免了一层原型链查找。beautiful!

感谢读者的阅读,这里react通过原型构造伪类,实现继承和复用,同时运用了避免原型跳跃等技巧提升性能,是很好的学习js原型和类继承原理的素材。如果觉得对您有一定的启发,欢迎点赞,动动小手手。

おすすめ

転載: juejin.im/post/7034517604161028109