【React源码 - ReactDom.render发生了什么】

在React开发中,在入口文件我们都会执行ReactDom.render来讲整个应用挂载在主document中,那其中发生了什么,React是如何讲我们写的JSX代码,一步一步更新Fiber进而挂载渲染的呢。本文主要是基于react@17.0.2的源码以及自己的理解来简单介绍一下这里面发生了什么。

流程总览

如下图所示,总体流程就是开发编写JSX代码之后会交由Babel来进行转移,并调用React.createElement转换为reactElement,然后生成虚拟DOM,通过render函数进一步更新filber渲染在页面上。所以本文主要是从源码角度来分析createElement和ReactElement函数的内部实现逻辑。
在这里插入图片描述

createElement

函数文件路径:packages/react/src/ReactElement.js

该函数接收三个参数(type、config、children),然后创建并返回一个给定类型的新ReactElement。主要做了一下一些事:

  1. 从config参数中拆分props属性和特殊属性
  2. 将子元素挂载到props.children上
  3. 给未设置的props属性设置默认值defaultProps
  4. 创建并返回一个ReactElement

由于开发环境下的代码主要是一些log或者warn的提示信息,所以这里不再分析,下面请看源码解析:
第一步:从config参数中拆分props属性和特殊属性

/*** 定义props的属性名,用于后面两次for遍历* 一次是遍历config配置,并将props属性拆出来* 一次是遍历defaultProps默认属性,给未赋值的属性给默认值*/let propName;// 保留props属性配置,不包括key、ref、self、sourceconst props = {};// config中的react内置的特殊属性let key = null;let ref = null;let self = null;let source = null;// 处理config参数,主要就是拆分props和特殊属性if (config != null) {// 将ref赋予有效值,用来保存当前的dom元素if (hasValidRef(config)) {ref = config.ref;// 开发环境提示warn信息if (__DEV__) {// ref属性设置成字符串的一个提示,后续版本会删除该用法warnIfStringRefCannotBeAutoConverted(config);}}// 以字符串的形式保留key属性if (hasValidKey(config)) {key = '' + config.key;}/*** 如果没有self、source属性则设置为null* 个人猜测可能是由于undefined可以被重写,所以这里改为null* 而且null比undefined更符合在这里的语义*  */self = config.__self === undefined ? null : config.__self;source = config.__source === undefined ? null : config.__source;// 去除key、ref、self、source特殊属性并赋值给props保存// RESERVED_PROPS定义的包含key、ref、self、source的对象for (propName in config) {if (hasOwnProperty.call(config, propName) &&!RESERVED_PROPS.hasOwnProperty(propName)) {props[propName] = config[propName];}}}

第二步:将子元素挂载到props.children上

/*** arguments是参数合集数组,包含上面的三个行参type、config、children...* 这里arguments.length - 2就是获取后面所有children的长度*/const childrenLength = arguments.length - 2;// 如果只有一个子元素,则直接赋值if (childrenLength === 1) {props.children = children;} else if (childrenLength > 1) {// 如果有多个,则通过数组来保存,并存储在props.children中const childArray = Array(childrenLength);for (let i = 0; i < childrenLength; i++) {childArray[i] = arguments[i + 2];}if (__DEV__) {if (Object.freeze) {Object.freeze(childArray);}}props.children = childArray;}

第三步:给未设置的props属性设置默认值defaultProps

// 遍历type元素的默认类型,给未设置的属性赋予默认值if (type && type.defaultProps) {const defaultProps = type.defaultProps;for (propName in defaultProps) {if (props[propName] === undefined) {props[propName] = defaultProps[propName];}}}

第四步:创建并返回一个ReactElement
通过将上面解析点属性配置,传递给ReactElement函数,然后返回一个ReactElement类型的DOM元素

return ReactElement(type,key,ref,self,source,ReactCurrentOwner.current,props,);

ReactElement

函数文件路径:packages/react/src/ReactElement.js
该函数使用工厂模式创建一个新的React Element,不在使用类的模式,所以不能通过new的方式来获取实例,该函数接收7个参数,并返回一个react element元素,不能用instanceof来判断该Element是不是React Element,只能通过Symbol.for(‘react.element’)来判断是否是React Element。react中是通过isValidElement方法判断元素是否为空对象并且$$typeof 是否为 REACT_ELEMENT_TYPE来判断的

/*** Verifies the object is a ReactElement.* See https://reactjs.org/docs/react-api.html#isvalidelement* @param {?object} object* @return {boolean} True if `object` is a ReactElement.* @final*/
export function isValidElement(object) {return (typeof object === 'object' &&object !== null &&object.$$typeof === REACT_ELEMENT_TYPE);
}
/*** Factory method to create a new React element. This no longer adheres to* the class pattern, so do not use new to call it. Also, instanceof check* will not work. Instead test $$typeof field against Symbol.for('react.element') to check* if something is a React Element.** @param {*} type 元素类型(dov、span...)* @param {*} props 子元素和元素基础属性* @param {*} key 元素的唯一标识,用于diff算法,节点对比* @param {string|object} ref 元素实例* @param {*} owner 父组件或者上级组件* @param {*} self 用于辅助判断this指向,后续会结合箭头函数去掉owner和字符串类型的ref参数* @param {*} source 保存文件名、行号和/或其他信息的资源数据* @internal*/
const ReactElement = function(type, key, ref, self, source, owner, props) {const element = {/*** 通过这个属性唯一标识是否是react element类型的元素* React在最后渲染的时候,会确认元素的类型是REACT_ELEMENT_TYPE* 表示组件元素的类型,值为十六进制或者Symbol值*/$$typeof: REACT_ELEMENT_TYPE,// 元素类型 (div、span...)type: type,// 元素唯一标识 diff中vmdom和真实dom对比时,首先判断keykey: key,// 组件实例ref: ref,// 向组件内部传递的属性数据props: props,// 父组件或者上级组件_owner: owner,};// 返回一个带有react element表示的dom元素return element;
};

ReactDOM.render

函数文件路径:packages/react-dom/src/client/ReactDOMLegacy.js
创建一个React Element元素之后,会传入render函数中进行渲染,render函数接收三个参数element、container、callback(可选), 然后调用legacyRenderSubtreeIntoContainer函数在container容器中调用react-reconciler中的updateContainer来更新队列以及整个Fiber。

/*** * @param {*} element 元素类型* @param {*} container element挂载在那些容器组件下* @param {*} callback 可选,渲染完成之后执行的回调* @returns */export function render(element: React$Element<any>,container: Container,callback: ?Function,
) {// 判断传入的父容器是否有效invariant(isValidContainer(container),'Target container is not a DOM element.',);return legacyRenderSubtreeIntoContainer(null,element,container,false,callback,);
}

从render到更新fiber进而更新真实dom渲染的大致流程如下:
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/226898.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

下载和安装AD14 - Altium Designer 14.3.20.54863

这个版本应该还支持XP 系统[doge]&#xff0c;总之就是想安装一下&#xff0c;没什么特别的意义。 下载 资源来自毛子网站&#xff1a;https://rutracker.net/forum/viewtopic.php?t5140739&#xff0c;带上个网页翻译插件就行。要用磁力链接下载&#xff0c;推荐用qbittorr…

UE4开发BIM程序 的 流程

某机构BIM设计研究中心主任马晓龙&#xff0c;他对编程颇有研究。今天他会用通俗易懂的语言来讲解基于游戏引擎UE4的BIM技术可视化应用。对于想要自己开发程序的设计师一定要读一下&#xff01; 1&#xff09;关于UE4——UE4是什么&#xff1f; 可以简单的理解为&#xff0c;一…

c基础学习(一)

学习网站&#xff1a; C语言的过去与未来 - C语言教程 - C语言网 (dotcpp.com)https://www.dotcpp.com/course/c-intros/ C 语言简介 - C 语言教程 - 网道 (wangdoc.com)https://wangdoc.com/clang/intro 变量&#xff1a; #include<stdio.h> /*引入头文件-- 标准…

docker入门概念详解

本篇文章对docker的一些基础概念和周边概念进行了详细解释。帮助你可以很好的理解docker是用来干什么的&#xff0c;docker是怎么工作的。其中有docker所运用到的技术解释&#xff0c;docker的不同发展版本&#xff0c;dokcer的架构&#xff0c;docker的生态等等详解。希望本片…

Unity中Shader裁剪空间推导(透视相机到裁剪空间的转化矩阵)

文章目录 前言一、简单看一下 观察空间—>裁剪空间—>屏幕空间 的转化1、观察空间&#xff08;右手坐标系、透视相机&#xff09;2、裁剪空间&#xff08;左手坐标系、且转化为了齐次坐标&#xff09;3、屏幕空间&#xff08;把裁剪坐标归一化设置&#xff09;4、从观察空…

Linux文件编程

目录 1、Linux系统提供的文件编程API 1.1打开文件&#xff1a;open 1.2创建文件creat函数 1.3写入文件write函数 1.4读取文件read函数 1.5文件光标位置lseek函数 2、另外一组文件编程API 2.1文件打开函数fopen 2.2读文件函数fread 2.3写文件函数fwrite 2.4文件光标位…

github鉴权失败

问题&#xff1a; 如上图所示 git push 时发生了报错&#xff0c;鉴权失败&#xff1b; 解决方案 Settings->Developer settings->Personal access tokens->Generate new token。创建新的访问密钥&#xff0c;勾选repo栏&#xff0c;选择有效期&#xff0c;为密钥命…

HarmonyOS4.0系统性深入开发08服务卡片架构

服务卡片概述 服务卡片&#xff08;以下简称“卡片”&#xff09;是一种界面展示形式&#xff0c;可以将应用的重要信息或操作前置到卡片&#xff0c;以达到服务直达、减少体验层级的目的。卡片常用于嵌入到其他应用&#xff08;当前卡片使用方只支持系统应用&#xff0c;如桌…

小型内衣洗衣机什么牌子好?口碑好的小型洗衣机

想必大家都知道&#xff0c;我们的内衣裤、袜子这些衣物对卫生方面的要求是比较的高&#xff0c;毕竟是贴身的衣物&#xff0c;因此是要分开清洗的&#xff0c;而不能够跟我们其他的大件衣服一起放入到大型洗衣机里进行混洗&#xff0c;很多就选择了分开单独的手洗&#xff0c;…

快速上手:Docker环境下的WordPress安装全攻略

在这篇文章中我会手把手地教你在Linux环境下使用Docker安装WordPress及相关应用。最终&#xff0c;你将会拥有一个安全、支持https的网站。别犹豫啦&#xff0c;跟着我一块儿搞起来吧&#xff01; 一、登录服务器 在之前的文章中有提到如何使用ssh命令登录到我们之前在AWS申请…

嵌入式SOC之通用图像处理之OSD文字信息叠加的相关实践记录

机缘巧合 机缘巧合下, 在爱芯元智的xx开发板下进行sdk的开发.由于开发板目前我拿到是当前最新的一版(估计是样品)&#xff0c;暂不公开开发板具体型号信息.以下简称板子 .很多优秀的芯片厂商,都会提供与开发板配套的完善的软件以及完善的技术支持(FAE)&#xff0c;突然觉得爱芯…

Kubernetes 的用法和解析(K8S 日志方案) -- 8

一、统一日志管理的整体方案 通过应用和系统日志可以了解Kubernetes集群内所发生的事情&#xff0c;对于调试问题和监视集群活动来说日志非常有用。对于大部分的应用来说&#xff0c;都会具有某种日志机制。因此&#xff0c;大多数容器引擎同样被设计成支持某种日志机制。 对…

android studio 将含有jni c++ 的library项目封装成jar并调用

请参考博客&#xff1a;android studio 4.1.1 将library项目封装成aar 并调用_android studio 4.1 aar release-CSDN博客 一 . 简单叙述 android studio 中可以创建Module 的两种属性&#xff0c;可以在build.gradle 中查看&#xff1a; 1. application属性&#xff1a;可以独…

前后端分离nodejs+vue医院预约挂号系统6nrhh

医院预约挂号系统主要有管理员、用户和医生三个功能模块。以下将对这三个功能的作用进行详细的剖析。 运行软件:vscode 前端nodejsvueElementUi 语言 node.js 框架&#xff1a;Express/koa 前端:Vue.js 数据库&#xff1a;mysql 开发软件&#xff1a;VScode/webstorm/hbuiderx均…

计算机视觉技术-锚框

目标检测算法通常会在输入图像中采样大量的区域&#xff0c;然后判断这些区域中是否包含我们感兴趣的目标&#xff0c;并调整区域边界从而更准确地预测目标的真实边界框&#xff08;ground-truth bounding box&#xff09;。 不同的模型使用的区域采样方法可能不同。 这里我们介…

图像分割实战-系列教程1:语义分割与实例分割概述

1、图像分割任务概述 1.1 图像分割 分割任务就是在原始图像中逐像素的找到你需要的轮廓 如图分别是&#xff08;物体检测&#xff09;与&#xff08;图像分割&#xff09;两个任务的效果对比&#xff0c;实际上会比检测任务要稍微麻烦一些&#xff0c;将图像会分为几个区域把…

学习笔记:R语言基础

文章目录 一、R语言简介二、选择R的原因三、R基本数据对象&#xff08;一&#xff09;向量&#xff08;二&#xff09;矩阵&#xff08;三&#xff09;数组&#xff08;四&#xff09;因子&#xff08;五&#xff09;列表&#xff08;六&#xff09;数据框&#xff08;七&#…

uni-app condition启动模式配置

锋哥原创的uni-app视频教程&#xff1a; 2023版uniapp从入门到上天视频教程(Java后端无废话版)&#xff0c;火爆更新中..._哔哩哔哩_bilibili2023版uniapp从入门到上天视频教程(Java后端无废话版)&#xff0c;火爆更新中...共计23条视频&#xff0c;包括&#xff1a;第1讲 uni…

DM、Oracle、GaussDB、Kingbase8(人大金仓数据库)和HIVE给列增加注释

DM数据库给列增加注释 1、创建表 CREATE TABLE test222 ( id int NOT NULL PRIMARY KEY, name varchar(1000) DEFAULT NULL, email varchar(1000) DEFAULT NULL, phone varchar(1000) DEFAULT NULL ) 2、给列添加注释 comment on column TEST222.NAME is 这是一个列注释; 例如…

数字身份验证:跨境电商如何应对账户安全挑战?

在数字化时代&#xff0c;随着跨境电商的蓬勃发展&#xff0c;账户安全问题逐渐成为行业和消费者关注的焦点。随着网络犯罪日益猖獗&#xff0c;用户的数字身份安全面临着更加复杂的威胁。本文将深入探讨数字身份验证在跨境电商中的重要性&#xff0c;并探讨各种创新技术和策略…