洞悉细节!react 16.8.6源码分析-5 hooks API

前言

作为一个前端页面仔和需求粉碎机,在日常的工作中重复雷同的业务需求,能够获得的提高是很有限的。要想跳出此山中,开阔新视野,笔者墙裂建议大家阅读市面上顶尖开源库的源码。这是学习和掌握js语言特性的绝佳机会(前端发展到现在,大型应用高度依赖框架,正常情况下普通开发者是没有机会接触底层的语言特性),同时也是深刻理解框架底层思维的契机。这里笔者选择react第一个开刀,市面上不少关于react源码分析的文章要么过于老旧,要么只截取部分代码或者是伪代码,笔者这里将选取react的16.8.6版本作为示例,从第0行开始,不漏过任何一个源码细节,和大家分享笔者在源码阅读过程中的体会。希望和大家共同进步,本系列博文中涉及的源码本人会放在git仓库中,链接在文末。

正文

React.lazy和forwardRef

//  lazy的构造函数
function lazy(ctor) {
   
  var lazyType = {
   
    $$typeof: REACT_LAZY_TYPE,
    _ctor: ctor,
    //  react使用这些值去储存结果
    // React uses these fields to store the result.
    _status: -1,
    _result: null
  };

  {
   
    //  在生产环境下,这些都会设置在对象上
    // In production, this would just set it on the object.
    var defaultProps = void 0;
    var propTypes = void 0;
    Object.defineProperties(lazyType, {
   
      defaultProps: {
   
        configurable: true,
        get: function () {
   
          return defaultProps;
        },
        set: function (newDefaultProps) {
   
          //  react不支持给lazy加载的组件修改默认属性,要么在定义的时候修改,要么在外面包上一层
          warning$1(false, 'React.lazy(...): It is not supported to assign `defaultProps` to ' + 'a lazy component import. Either specify them where the component ' + 'is defined, or create a wrapping component around it.');
          defaultProps = newDefaultProps;
          //  和生产环境的行为更接近
          //  设置可枚举类型
          // Match production behavior more closely:
          Object.defineProperty(lazyType, 'defaultProps', {
   
            enumerable: true
          });
        }
      },
      propTypes: {
   
        configurable: true,
        get: function () {
   
          return propTypes;
        },
        set: function (newPropTypes) {
   
          //  react不支持给懒加载组件设置属性类型
          warning$1(false, 'React.lazy(...): It is not supported to assign `propTypes` to ' + 'a lazy component import. Either specify them where the component ' + 'is defined, or create a wrapping component around it.');
          propTypes = newPropTypes;
          // Match production behavior more closely:
          Object.defineProperty(lazyType, 'propTypes', {
   
            enumerable: true
          });
        }
      }
    });
  }

  return lazyType;
}

//  前向ref
function forwardRef(render) {
   
  {
   
    //  感觉就是一堆校验
    if (render != null && render.$$typeof === REACT_MEMO_TYPE) {
   
      //  如果render不为null且其类型为REACT_MEMO_TYPE,抛错
      warningWithoutStack$1(false, 'forwardRef requires a render function but received a `memo` ' + 'component. Instead of forwardRef(memo(...)), use ' + 'memo(forwardRef(...)).');
    } else if (typeof render !== 'function') {
   
      //  如果不是函数,抛错
      warningWithoutStack$1(false, 'forwardRef requires a render function but was given %s.', render === null ? 'null' : typeof render);
    } else {
   
      !(
        //  0参数的时候不报错,因为这可能是因为参数是对象
      // Do not warn for 0 arguments because it could be due to usage of the 'arguments' object
      //  如果参数数组长度不为0或2,抛错:forwardRef只接受2个参数,属性值和ref,'你忘记传ref'或'多出来的参数都会被省略'
      render.length === 0 || render.length === 2) ? warningWithoutStack$1(false, 'forwardRef render functions accept exactly two parameters: props and ref. %s', render.length === 1 ? 'Did you forget to use the ref parameter?' : 'Any additional parameter will be undefined.') : void 0;
    }

    //  如果不满足之前的条件且render不为空
    if (render != null) {
   
      //  如果render上存在defaultProps或者propTypes,抛错:forwardRef的渲染函数不支持propTypes或者defaultProps,你实际上传入了一个react组件是吗
      !(render.defaultProps == null && render.propTypes == null) ? warningWithoutStack$1(false, 'forwardRef render functions do not support propTypes or defaultProps. ' + 'Did you accidentally pass a React component?') : void 0;
    }
  }

  return {
   
    $$typeof: REACT_FORWARD_REF_TYPE,
    render: render
  };
}

接下来的内容主要是部分react方法的实现,到这里大家应该会逐步看到一些熟悉的方法,首先介绍的lazy和forwardRef

组件有效判断与hooksAPI定义


//  判断是否是元素的可用类型
function isValidElementType(type) {
   
  //  字符串,函数,react片段或者组件
  return typeof type === 'string' || typeof type === 'function' ||
  //  这里的类型可能是symbol或者是数字,如果使用了降级的写法
  // Note: its typeof might be other than 'symbol' or 'number' if it's a polyfill.
  //  后面的这些type要调一次$$typeof
  type === REACT_FRAGMENT_TYPE || type === REACT_CONCURRENT_MODE_TYPE || type === REACT_PROFILER_TYPE || type === REACT_STRICT_MODE_TYPE || type === REACT_SUSPENSE_TYPE || typeof type === 'object' && type !== null && (type.$$typeof === REACT_LAZY_TYPE || type.$$typeof === REACT_MEMO_TYPE || type.$$typeof === REACT_PROVIDER_TYPE || type.$$typeof === REACT_CONTEXT_TYPE || type.$$typeof === REACT_FORWARD_REF_TYPE);
}

//  纯函数版本的pureComponent,第一个参数是个函数
function memo(type, compare) {
   
  {
   
    //  如果不是react类型
    if (!isValidElementType(type)) {
   
      //  memo的第一个参数必须是组件
      warningWithoutStack$1(false, 'memo: The first argument must be a component. Instead ' + 'received: %s', type === null ? 'null' : typeof type);
    }
  }
  return {
   
    $$typeof: REACT_MEMO_TYPE,
    type: type,
    compare: compare === undefined ? null : compare
  };
}

//  返回当前的dispatcher
function resolveDispatcher() 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值