返回顶部
首页 > 资讯 > 前端开发 > JavaScript >ReactcreateElement方法使用原理分析介绍
  • 169
分享到

ReactcreateElement方法使用原理分析介绍

2024-04-02 19:04:59 169人浏览 独家记忆
摘要

目录摘要1.创建方法2.处理type3.处理config4.处理children5.对比真正的React.createElement源码摘要 在上一篇说过,React创建元素有两种方

摘要

在上一篇说过,React创建元素有两种方式:

第一种是通过jsX方式创建,第二种是通过React.createElement方法创建。但是通过JSX创建React元素的方式,最终也会经过babel进行转换,再用React.createElement进行元素创建。

而这一篇文章,主要是讲一下React.createElement是如何创建React元素的。

1.创建方法

为了了解React.createElement这个方法,我们自己手动去实现一个简易版的。

OK,首先我们通过React.createElement方法创建一个React元素,并且打印出来:

    const b = React.createElement('div',{data: '1234'},'oneTwo')
    console.log(b);

打印出来的结果为:

所以,如果我们要实现出来React.createElement这个方法,定义的时候我们可以这么写:

function createElement(type, config, children){
  let props = {}
  let myType = ''
  let key = ''
  let ref = ''
  return {
    $$typeOf: 'react.element',
    type: myType,
    props,
    key,
    ref
  }
}

这里我们不管**$$typeOf**这个变量,只考虑其他的变量,最终返回的对象应该是这个数据结构

2.处理type

好了,方法的定义已经写完了。针对于传进来的这三个参数,我们一个一个看。

第一个参数type,它代表的是创建React元素的类型。

这里面可以是传统的html元素,例如div,h1,span等标签。

也可以是一个React组件(注意这里哦)。

而React创建组件又有两种方式,所以type的值,有三种数据类型:

(1)字符串:例如"div",“h1”,“span”,"p"等标签

(2)函数:通过函数的方式创建React组件

(3)类:通过class的方式创建React组件

而这个时候就有一个问题!

class Demo {
}
typeof Demo

上面的值应该为什么呢?答案是function,所以在这里我们只需要考虑type为string和function两种类型即可。

所以我们可以写一个判断类型的方法:

function isValidElementType(type){
  if(typeof type === 'string' || typeof type === 'function'){
    return true;
  }
  return false;
}

在我们的主方法里面引用:

function createElement(type, config, children){
  let props = {}
  let myType = ''
  let key = ''
  let ref = ''
  if(isValidElementType(type)){
    myType = type;
  }
  return {
    $$typeOf: 'react.element',
    type: myType,
    props,
    key,
    ref
  }
}

3.处理config

对于React.createElement方法的第二个参数,接收看一个对象。而对象下所有的属性,都会被放在props里面。

这句话对不对呢?其实也不是很对,是有特例的,如果在这个对象下,有key或者ref这两个属性。它是不会被放在props里面的,而是直接赋值给key和ref

Ok,有了上面的话,我们就可以对config进行处理了:

  if(config != null){
    if(config.ref){
      ref = config.ref
    }
    if(config.key){
      key = config.key
    }
    for(let propName in config){
      if(!(['ref','key'].includes(propName))){
        props[propName] = config[propName]
      }
    }
  }

我们只需要把config的key和ref分别给到我们返回对象里面的key和ref。再便利一下config,拿出来的属性和值把key和ref排除。最终我们的config属性就处理好了。

4.处理children

最后一步就是处理children属性了。而React.createElement方法的第三个参数,也可以是第四个参数(就是后面的所有参数)。都可以为字符串,或者是React元素。

这里的React元素我们不管它是通过JSX创建的,还是通过React.createElement方法创建的都可以

而参数的情况分两种:

第一种是只有三个参数,也就是children为一个值。这个时候props里面的children就是该字符串。

第二种是参数大于三个,这个时候,props里面的children是一个数组,数组里的元素就是后面的所有参数。

OK,有了上面的基础,就可以对children进行处理了:

  let childrenLength = arguments.length - 2
  if(childrenLength === 1){
    props.children = children
  }else if(childrenLength > 1){
    let children = new Array(childrenLength)
    for(let i = 0;i<childrenLength;i++){
      children[i] = arguments[i+2]
    }
    props.children = children
  }

这里通过arguments来判断参数的个数,进而确定分支条件。

然后再根据情况,确定props里的children。

最后再贴上完整的createElement方法(简易版):

function createElement(type, config, children){
  let props = {}
  let myType = ''
  let key = ''
  let ref = ''
  if(isValidElementType(type)){
    myType = type;
  }
  if(config != null){
    if(config.ref){
      ref = config.ref
    }
    if(config.key){
      key = config.key
    }
    for(let propName in config){
      if(!(['ref','key'].includes(propName))){
        props[propName] = config[propName]
      }
    }
  }
  let childrenLength = arguments.length - 2
  if(childrenLength === 1){
    props.children = children
  }else if(childrenLength > 1){
    let children = new Array(childrenLength)
    for(let i = 0;i<childrenLength;i++){
      children[i] = arguments[i+2]
    }
    props.children = children
  }
  return {
    $$typeOf: 'react.element',
    type: myType,
    props,
    key,
    ref
  }
}

5.对比真正的React.createElement源码

OK,上面只是实现了一个比较简单的React.createElement方法,但是懂了其中的过程,我们就可以看一下真正的React.createElement源码:

isValidElementType方法

function isValidElementType(type) {
  if (typeof type === 'string' || typeof type === 'function') {
    return true;
  } // Note: typeof might be other than 'symbol' or 'number' (e.g. if it's a polyfill).
  if (type === REACT_FRAGMENT_TYPE || type === REACT_PROFILER_TYPE || enableDebugTracing  || type === REACT_STRICT_MODE_TYPE || type === REACT_SUSPENSE_TYPE || type === REACT_SUSPENSE_LIST_TYPE || enableLegacyHidden  || type === REACT_OFFSCREEN_TYPE || enableScopeapi  || enableCacheElement  || enableTransitionTracing ) {
    return true;
  }
  if (typeof type === 'object' && type !== null) {
    if (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 || // This needs to include all possible module reference object
    // types supported by any Flight configuration anywhere since
    // we don't know which Flight build this will end up being used
    // with.
    type.$$typeof === REACT_MODULE_REFERENCE || type.getModuleId !== undefined) {
      return true;
    }
  }
  return false;
}

这里面也主要就是判断type的类型,不过判断情况多了几种React自带的元素类型。

createElement方法

function createElement(type, config, children) {
  var propName; // Reserved names are extracted
  var props = {};
  var key = null;
  var ref = null;
  var self = null;
  var source = null;
  if (config != null) {
    if (hasValidRef(config)) {
      ref = config.ref;
      {
        warnIfStringRefCannotBeAutoConverted(config);
      }
    }
    if (hasValidKey(config)) {
      {
        checkKeyStrinGCoercion(config.key);
      }
      key = '' + config.key;
    }
    self = config.__self === undefined ? null : config.__self;
    source = config.__source === undefined ? null : config.__source; // Remaining properties are added to a new props object
    for (propName in config) {
      if (hasOwnProperty.call(config, propName) && !RESERVED_PROPS.hasOwnProperty(propName)) {
        props[propName] = config[propName];
      }
    }
  } // Children can be more than one argument, and those are transferred onto
  // the newly allocated props object.
  var childrenLength = arguments.length - 2;
  if (childrenLength === 1) {
    props.children = children;
  } else if (childrenLength > 1) {
    var childArray = Array(childrenLength);
    for (var i = 0; i < childrenLength; i++) {
      childArray[i] = arguments[i + 2];
    }

    {
      if (Object.freeze) {
        Object.freeze(childArray);
      }
    }
    props.children = childArray;
  } // Resolve default props
  if (type && type.defaultProps) {
    var defaultProps = type.defaultProps;

    for (propName in defaultProps) {
      if (props[propName] === undefined) {
        props[propName] = defaultProps[propName];
      }
    }
  }
  {
    if (key || ref) {
      var displayName = typeof type === 'function' ? type.displayName || type.name || 'Unknown' : type;
      if (key) {
        defineKeyPropWarningGetter(props, displayName);
      }
      if (ref) {
        defineRefPropWarningGetter(props, displayName);
      }
    }
  }
  return ReactElement(type, key, ref, self, source, ReactCurrentOwner.current, props);
};

这个方法主要是对config和children进行处理。

其余的部分就不粘过来了,对源码感兴趣的可以自己打断点尝试一哈!

到此这篇关于React createElement方法使用原理分析介绍的文章就介绍到这了,更多相关React createElement内容请搜索编程网以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程网!

--结束END--

本文标题: ReactcreateElement方法使用原理分析介绍

本文链接: https://lsjlt.com/news/166582.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

猜你喜欢
  • ReactcreateElement方法使用原理分析介绍
    目录摘要1.创建方法2.处理type3.处理config4.处理children5.对比真正的React.createElement源码摘要 在上一篇说过,React创建元素有两种方...
    99+
    2024-04-02
  • Reactthis.setState方法使用原理分析介绍
    目录摘要1.异步的setState2.多个setState方法3.手动实现mySetState摘要 这一篇文章,主要是简单的实现一下this.setState方法,为了实现该方法,就...
    99+
    2024-04-02
  • VueNextTick介绍与使用原理
    目录一、NextTick是什么定义理解为什么要有nexttick二、使用场景三、实现原理一、NextTick是什么 定义 在下次 DOM 更新循环结束之后执行延迟回调。在修改数据之后...
    99+
    2022-11-13
    Vue NextTick Vue NextTick的作用
  • JavaScriptreduce方法使用方法介绍
    目录1. reduce方法的使用2. reduce数组的使用场景2.1 扁平化数组2.2 数组去重2.3 计算数组最大/最小值2.4 数组求和2.5 计算数组中元素的出现次数3. 操...
    99+
    2022-11-13
    JavaScript reduce JS reduce
  • JavaScript闭包原理与使用介绍
    目录1. 认识闭包2. 变量的作用域和生命周期2.1 变量的作用域2.2 变量的生命周期3. 闭包的概念及其作用3.1 闭包的概念3.2 闭包的应用3.2.1 保存私有变量3.2.2...
    99+
    2022-11-13
    JavaScript闭包 JS闭包
  • Repo工作原理和使用介绍
    目录1. 概要2. 工作原理2.1 项目清单库(.repo/manifests)2.2 repo脚本库(.repo/repo)2.3 仓库目录和工作目录3. 使用介绍3.1 init...
    99+
    2024-04-02
  • Vuesnippets插件原理与使用介绍
    目录vue-snippetssnippets是什么vue-3-snippets插件支持的功能vue-snippets 随着开发者的年限的增加,不仅头发有点少,重复的代码也不断的增多,...
    99+
    2022-11-13
    Vue snippets原理 Vue snippets插件
  • chatgpt的算法原理介绍
    chatgpt的算法原理是基于GPT-3,先通过人工标注方式训练出强化学习的冷启动模型与reward反馈模型,最后通过强化学习的方式...
    99+
    2023-02-09
    chatgpt
  • Ribbon负载均衡算法原理与使用介绍
    负载均衡算法:rest接口第几次请求数 % 服务器集群总数量 = 实际调用服务器位置下标 ,每次服务重启动后rest接口计数从1开始。 List<ServiceInstance...
    99+
    2024-04-02
  • 浅析node Async异步处理模块用例分析及常用方法介绍
    最近在研究nodejs,令我感受比较深的是……熟悉js代码的地球人都知道,js的加载顺序很重要!很重要!!那么问题来了,在编写node的时候,会在后台去请求很多接口(我们公司是与java后台交接数据的),接...
    99+
    2022-06-04
    模块 常用 方法
  • Pinia介绍及工作原理解析
    目录什么是Pinia如何使用Pinia安装创建store在组件中使用store在模板中使用storePinia是如何工作的什么是Pinia Pinia是Vue 3的状态管理库,它提...
    99+
    2023-03-06
    Pinia工作原理 Pinia原理
  • mysqldump的使用方法介绍
    这篇文章主要介绍了mysqldump的使用方法介绍,具有一定借鉴价值,需要的朋友可以参考下。下面就和我一起来看看吧。1、说明mysqldump在库被删除的情况下,无法直接从文件恢复,需要手动新建同名库,才能从文件恢复数据。2、语法shell...
    99+
    2023-06-15
  • String.format()方法的使用介绍
    String.format() 方法中的 % 符号用作占位符,用于将值插入字符串中。它用于使用特定值(例如整数、浮点数或字符串)格式化字符串。% 符号后面跟着一个字母,指定要插入的值的类型,例如 %d 表示整数,%s 表示字符串。要插入的...
    99+
    2023-09-07
    java 开发语言 spring servlet
  • Kotlin ContentProvider使用方法介绍
    目录1、注册ContentProvider2、内容URI内容URI的标准格式通配符3、创建自己的ContentProvider4、访问其他程序中的数据1、注册ContentProvi...
    99+
    2024-04-02
  • AndroidLeakCanary的使用方法介绍
    目录1.LeakCanary 如何自动初始化2.LeakCanary如何检测内存泄漏2.1LeakCanary初始化时做了什么2.2LeakCanary如何触发检测2.3LeakCa...
    99+
    2024-04-02
  • Promise的原理和基础用法介绍
    这篇文章主要介绍“Promise的原理和基础用法介绍”,在日常操作中,相信很多人在Promise的原理和基础用法介绍问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”Promis...
    99+
    2024-04-02
  • TIDB简介及TIDB部署、原理和使用介绍
    TiDB简介及TiDB部署、原理和使用介绍 从MySQL架构到TiDB 数据库分类 ​ 介绍TiDB数据库之前,先引入使用场景。如今的数据库种类繁多,RDBMS(关系型数据库)、NoSQL(Not Only SQL)、NewSQL,在数据库...
    99+
    2023-08-17
    tidb 数据库 mysql 大数据 etl工程师
  • ReactHooks使用方法全方位介绍
    目录hooks介绍useState(保存组件状态)useEffect()useCallback(记忆函数)useMemo(记忆组件)useRef(保存引用值)useReducerus...
    99+
    2023-03-19
    React Hooks React Hooks方法
  • android之HttpPostHttpGet使用方法介绍
    直接讲用法,先知道怎么用,再知道怎么回事 1、HttpPost 代码如下: try{ //创建连接 HttpClient httpClient = new DefaultHt...
    99+
    2022-06-06
    方法 Android
  • android startActivityForResult的使用方法介绍
    Activity 跳转 都知道用startActivity(Intent)但是如果下面情况呢?Activity1 跳转到 Activity2  但是还需要在Activ...
    99+
    2022-06-06
    方法 Android
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作