当前位置: 首页 > news >正文

React16源码: React中的updateHostComponent的源码实现

updateHostComponent


1 )概述

  • completeWork 阶段的 HostComponent 处理,继续前文所述
  • 在更新的逻辑里面,调用了 updateHostComponent
  • 进行前后props对应的dom的attributes变化的对比情况
  • 这个方法也是根据不同环境来定义的,我们这里只专注于 react-dom 环境

2 )源码

定位到 packages/react-reconciler/src/ReactFiberCompleteWork.js#L586

这里是 updateHostComponent 调用的地方

updateHostComponent(current,workInProgress,type,newProps,rootContainerInstance,
);if (current.ref !== workInProgress.ref) {markRef(workInProgress);
}

接着,进入其定义

updateHostComponent = function(current: Fiber,workInProgress: Fiber,type: Type,newProps: Props,rootContainerInstance: Container,
) {// If we have an alternate, that means this is an update and we need to// schedule a side-effect to do the updates.const oldProps = current.memoizedProps;// 全等对象,没有变化过,直接 returnif (oldProps === newProps) {// In mutation mode, this is sufficient for a bailout because// we won't touch this node even if children changed.return;}// If we get updated because one of our children updated, we don't// have newProps so we'll have to reuse them.// TODO: Split the update API as separate for the props vs. children.// Even better would be if children weren't special cased at all tho.// 获取 dom 和 contextconst instance: Instance = workInProgress.stateNode;const currentHostContext = getHostContext();// TODO: Experiencing an error where oldProps is null. Suggests a host// component is hitting the resume path. Figure out why. Possibly// related to `hidden`.// 注意这里,const updatePayload = prepareUpdate(instance,type,oldProps,newProps,rootContainerInstance,currentHostContext,);// TODO: Type this specific to this type of component.workInProgress.updateQueue = (updatePayload: any);// If the update payload indicates that there is a change or if there// is a new ref we mark this as an update. All the work is done in commitWork.if (updatePayload) {markUpdate(workInProgress);}
};
  • 进入 prepareUpdate
    // 忽略 DEV 判断,这里直接 return 了 diffProperties 的调用
    export function prepareUpdate(domElement: Instance,type: string,oldProps: Props,newProps: Props,rootContainerInstance: Container,hostContext: HostContext,
    ): null | Array<mixed> {if (__DEV__) {const hostContextDev = ((hostContext: any): HostContextDev);if (typeof newProps.children !== typeof oldProps.children &&(typeof newProps.children === 'string' ||typeof newProps.children === 'number')) {const string = '' + newProps.children;const ownAncestorInfo = updatedAncestorInfo(hostContextDev.ancestorInfo,type,);validateDOMNesting(null, string, ownAncestorInfo);}}return diffProperties(domElement,type,oldProps,newProps,rootContainerInstance,);
    }
    
    • 进入 diffProperties
      // 这个方法和前文中的 setInitialProperties 有一定的类似, 根据不同的节点做不同的操作
      // Calculate the diff between the two objects.
      export function diffProperties(domElement: Element,tag: string,lastRawProps: Object,nextRawProps: Object,rootContainerElement: Element | Document,
      ): null | Array<mixed> {if (__DEV__) {validatePropertiesInDevelopment(tag, nextRawProps);}let updatePayload: null | Array<any> = null;let lastProps: Object;let nextProps: Object;switch (tag) {case 'input':lastProps = ReactDOMInput.getHostProps(domElement, lastRawProps);nextProps = ReactDOMInput.getHostProps(domElement, nextRawProps);updatePayload = [];break;case 'option':lastProps = ReactDOMOption.getHostProps(domElement, lastRawProps);nextProps = ReactDOMOption.getHostProps(domElement, nextRawProps);updatePayload = [];break;case 'select':lastProps = ReactDOMSelect.getHostProps(domElement, lastRawProps);nextProps = ReactDOMSelect.getHostProps(domElement, nextRawProps);updatePayload = [];break;case 'textarea':lastProps = ReactDOMTextarea.getHostProps(domElement, lastRawProps);nextProps = ReactDOMTextarea.getHostProps(domElement, nextRawProps);updatePayload = [];break;default:lastProps = lastRawProps;nextProps = nextRawProps;if (typeof lastProps.onClick !== 'function' &&typeof nextProps.onClick === 'function') {// TODO: This cast may not be sound for SVG, MathML or custom elements.trapClickOnNonInteractiveElement(((domElement: any): HTMLElement));}break;}assertValidProps(tag, nextProps);let propKey;let styleName;let styleUpdates = null;// 那么接下去会有两个循环// 第一个循环是循环 lastProps, 就是上一次渲染的结果产生的props// 这是第一次大循环: 找到在旧的props上有的属性,在新的props上没有的,也就是找到前后对比中删除的propsfor (propKey in lastProps) {// 对 新旧 props 进行循环判断: 新props有key 或 旧props没有key 或 旧props为null 则跳过此keyif (nextProps.hasOwnProperty(propKey) ||!lastProps.hasOwnProperty(propKey) ||lastProps[propKey] == null) {// 符合这个条件,不是被删除的属性,不会加到最后的 updatePayloadcontinue;}// 对符合被删除属性来说,进行删除 style 的操作if (propKey === STYLE) {const lastStyle = lastProps[propKey];for (styleName in lastStyle) {if (lastStyle.hasOwnProperty(styleName)) {if (!styleUpdates) {styleUpdates = {};}styleUpdates[styleName] = '';}}// 后面的其他判断,都没有做什么事情,可以跳过了} else if (propKey === DANGEROUSLY_SET_INNER_HTML || propKey === CHILDREN) {// Noop. This is handled by the clear text mechanism.} else if (propKey === SUPPRESS_CONTENT_EDITABLE_WARNING ||propKey === SUPPRESS_HYDRATION_WARNING) {// Noop} else if (propKey === AUTOFOCUS) {// Noop. It doesn't work on updates anyway.} else if (registrationNameModules.hasOwnProperty(propKey)) {// This is a special case. If any listener updates we need to ensure// that the "current" fiber pointer gets updated so we need a commit// to update this element.if (!updatePayload) {updatePayload = [];}} else {// For all other deleted properties we add it to the queue. We use// the whitelist in the commit phase instead.// 注意这里,加入 updatePayload 的方式是 一次加入 key, value 这2个(updatePayload = updatePayload || []).push(propKey, null);}}// 这是第二次大循环, nextProps 就是新的propsfor (propKey in nextProps) {// 处理 新旧 propsconst nextProp = nextProps[propKey];const lastProp = lastProps != null ? lastProps[propKey] : undefined;// 新props没有这个key(这个key在原型链上,不在自己),或 两个 prop 相同,或两个prop 都为 nullif (!nextProps.hasOwnProperty(propKey) ||nextProp === lastProp ||(nextProp == null && lastProp == null)) {// 符合上述条件跳过continue;}// 对于 style 类型的 props 的处理, 判断每个 style 的key是否有变化// 下面会有两个循环来处理if (propKey === STYLE) {if (__DEV__) {if (nextProp) {// Freeze the next style object so that we can assume it won't be// mutated. We have already warned for this in the past.Object.freeze(nextProp);}}if (lastProp) {// Unset styles on `lastProp` but not on `nextProp`.for (styleName in lastProp) {if (lastProp.hasOwnProperty(styleName) &&(!nextProp || !nextProp.hasOwnProperty(styleName))) {if (!styleUpdates) {styleUpdates = {};}styleUpdates[styleName] = '';}}// Update styles that changed since `lastProp`.for (styleName in nextProp) {if (nextProp.hasOwnProperty(styleName) &&lastProp[styleName] !== nextProp[styleName]) {if (!styleUpdates) {styleUpdates = {};}styleUpdates[styleName] = nextProp[styleName];}}} else {// Relies on `updateStylesByID` not mutating `styleUpdates`.if (!styleUpdates) {if (!updatePayload) {updatePayload = [];}updatePayload.push(propKey, styleUpdates);}styleUpdates = nextProp;}} else if (propKey === DANGEROUSLY_SET_INNER_HTML) {const nextHtml = nextProp ? nextProp[HTML] : undefined;const lastHtml = lastProp ? lastProp[HTML] : undefined;if (nextHtml != null) {// 两个html不相等则加入if (lastHtml !== nextHtml) {(updatePayload = updatePayload || []).push(propKey, '' + nextHtml);}} else {// TODO: It might be too late to clear this if we have children// inserted already.}} else if (propKey === CHILDREN) {// 对于 children 的处理if (lastProp !== nextProp &&(typeof nextProp === 'string' || typeof nextProp === 'number')) {// 不同则加入(updatePayload = updatePayload || []).push(propKey, '' + nextProp);}} else if (propKey === SUPPRESS_CONTENT_EDITABLE_WARNING ||propKey === SUPPRESS_HYDRATION_WARNING) {// Noop} else if (registrationNameModules.hasOwnProperty(propKey)) {// 这里是事件绑定相关的处理if (nextProp != null) {// We eagerly listen to this even though we haven't committed yet.if (__DEV__ && typeof nextProp !== 'function') {warnForInvalidEventListener(propKey, nextProp);}ensureListeningTo(rootContainerElement, propKey);}if (!updatePayload && lastProp !== nextProp) {// This is a special case. If any listener updates we need to ensure// that the "current" props pointer gets updated so we need a commit// to update this element.updatePayload = [];}} else {// For any other property we always add it to the queue and then we// filter it out using the whitelist during the commit.// 上面都没找到,这个属性是新增属性,直接加入(updatePayload = updatePayload || []).push(propKey, nextProp);}}// 最终处理加入 styleUpdatesif (styleUpdates) {(updatePayload = updatePayload || []).push(STYLE, styleUpdates);}// 最终返回return updatePayload;
      }
      
    • diffProperties 里的 updatePayload 一开始是一个空的数组,并且最终被return
    • 对于 completeWork 来说,拿到的 updatePayload,就是 diffPropertiesprepareUpdate 返回过来的内容
    • 接下去,会有一个判断 if (updatePayload) {} 也就是说空数组也是符合这个判断条件的, 也会执行 markUpdate
    • 上述标记之后,在后续的 commit 的时候进行对应的操作
  • 以上是 updateHostComponent 的过程
    • 具体细节,参考代码里标注的中文文档和源码
    • vdom其实就是这些东西,通过props来进行 attributes 的判断和处理变化的过程
    • 主要是 整个 diffProperties 的处理

相关文章:

React16源码: React中的updateHostComponent的源码实现

updateHostComponent 1 &#xff09;概述 在 completeWork 阶段的 HostComponent 处理&#xff0c;继续前文所述在更新的逻辑里面&#xff0c;调用了 updateHostComponent进行前后props对应的dom的attributes变化的对比情况这个方法也是根据不同环境来定义的&#xff0c;我们这…...

uniapp导入uView组件库

目录 准备工作 1. 新建一个项目 2. 导入uview组件库 3. 关于SCSS 配置步骤 1. 引入uView主JS库 2. 在引入uView的全局SCSS 3. 引入uView基础样式 4. 配置easycom组件模式 添加效果实验运行即可成功 准备工作 1. 新建一个项目 2. 导入uview组件库 在进行配置之前&#x…...

防御保护----防火墙的安全策略、NAT策略实验

实验拓扑&#xff1a; 实验要求&#xff1a; 1.生产区在工作时间&#xff08;9&#xff1a;00-18&#xff1a;00&#xff09;内可以访问DMZ区&#xff0c;仅可以访问http服务器&#xff1b; 2.办公区全天可以访问DMZ区&#xff0c;其中10.0.2.10可以访问FTP服务器和HTTP服务器…...

# 安徽锐锋科技IDMS系统简介

IDMS 由安徽锐锋科技独立开发 该系统负责和海算以及UE\UNITY的无缝衔接并具备远程数据库访问、高速数据库的自动创建及数据存储、支持MQTT等多种物联网接口&#xff0c;支持多种算法。主要完成由于物料、人员、生产、故障、不良异常、订单异常带来的生产损失&#xff0c;通过海…...

Notepad在文件中查找多行相同内容的文字

Notepad在文件中查找多行相同的内容 查找&#xff1a;打开 Notepad软件&#xff0c; Ctrl F 查找 。输入关键词&#xff0c; 点击【在当前文件中查找】。 复制&#xff1a;直接在下方的【搜索结果】复制。 Notepad提取含有特定字符串的行 详情见&#xff1a; https://blog…...

Python高超音速导弹

Python高超音速导弹的全自动化开发研发具有重要性的原因如下&#xff1a; 提高研发效率&#xff1a;全自动化开发可以通过自动化工具和流程&#xff0c;快速完成各种任务&#xff0c;包括代码编写、测试、集成和部署等。这样可以大大提高研发效率&#xff0c;缩短开发周期。 减…...

Java七大排序详解

排序 排序的概念 所谓排序 &#xff0c;就是让一串记录&#xff0c;按照其中某些或者某个关键字的大小&#xff0c;递增或递减的排列起来的操作。 稳定性&#xff1a;就比如在待排序的序列中&#xff0c;存在多个具有相同关键字的记录 &#xff0c;如果经过排序这些相同的关键…...

图像旋转角度计算并旋转

#!/usr/bin/python3 # -*- coding: utf-8 -*- import cv2 import numpy as np import timedef Rotate(img, angle0.0,fill0):"""旋转:param img:待旋转图像:param angle: 旋转角度:param fill&#xff1a;填充方式&#xff0c;默认0黑色填充:return: img: 旋转后…...

通过curl访问k8s集群获取证书或token的方式

K8S安全控制框架主要由下面3个阶段进行控制&#xff0c;每一个阶段都支持插件方式&#xff0c;通过API Server配置来启用插件。 1. Authentication&#xff08;认证&#xff09; 2. Authorization&#xff08;授权&#xff09; 3. Admission Control&#xff08;准入控制&#…...

苍穹外卖-前端部分(持续更新中)

d 第二种&#xff1a;cmd中输入 vue ui进入图形化界面选择npm,vue2进行创建 先将创建的Vue框架导入Vsocde开发工具 然后ctrshiftp 输入npm 点击serve将项目启动 下这种写法跨域会报错&#xff1a; 解决方法&#xff1a;...

windows用mingw(g++)编译opencv,opencv_contrib,并install安装

windows下用mingw编译opencv貌似不支持cuda&#xff0c;选cuda会报错&#xff0c;我无法解决&#xff0c;所以没选cuda&#xff0c;下面两种编译方式支持。 如要用msvc编译opencv&#xff0c;参考我另外一篇文章 https://blog.csdn.net/weixin_44733606/article/details/1357…...

JDWP 协议及实现

JDWP 的协议细节并通过实际调试中的例子展开揭示 JDWP 的实现机制,JDWP 是 Java Debug Wire Protocol 的缩写,它定义了调试器(debugger)和被调试的 Java 虚拟机(target vm)之间的通信协议。 JDWP 协议介绍 这里首先要说明一下 debugger 和 target vm。Target vm 中运行…...

利用ADS建立MIPI D-PHY链路仿真流程

根据MIPI D-PHY v1.2规范中对于互连电气参数的定义,本次仿真实例中,需要重点关注如下的设计参数: 1. 差分信号的插入损耗Sddij和回拨损耗Sddii; 2. 模式转换损耗Sdcxx、Scdxx; 3. 数据线与时钟线之间的串扰耦合(远、近端)。 设计者还可以结合CTS中的补充…...

【大根堆】【C++算法】871 最低加油次数

作者推荐 【动态规划】【map】【C算法】1289. 下降路径最小和 II 本文涉及知识点 大根堆 优先队列 LeetCode:871最低加油次数 汽车从起点出发驶向目的地&#xff0c;该目的地位于出发位置东面 target 英里处。 沿途有加油站&#xff0c;用数组 stations 表示。其中 statio…...

SpringBoot的自动装配原理

一、SpringBootConfiguration注解的作用 SpringBootApplication注解是SpringBoot项目的核心注解,加在启动引导类上。点击进去可以发现SpringBootApplication注解是一个组合注解。其中SpringBootConfiguration和EnableAutoConfiguration是由Spring提供的,剩下的注解是由JDK提供的…...

嵌入式驱动开发需要会哪些技能?

嵌入式驱动开发是指在嵌入式系统中编写驱动程序&#xff0c;实现设备与计算机之间的通信。嵌入式驱动开发是指编写设备驱动程序&#xff0c;实现设备与计算机之间的通信。以下是一些嵌入式驱动开发的具体操作方法: 1&#xff09;了解硬件设备结构&#xff1a;在进行嵌入式驱动…...

Leetcode:二分搜索树层次遍历

题目&#xff1a; 给你二叉树的根节点 root &#xff0c;返回其节点值的 层序遍历 。 &#xff08;即逐层地&#xff0c;从左到右访问所有节点&#xff09;。 示例&#xff1a; 示例 1&#xff1a; 输入&#xff1a;root [3,9,20,null,null,15,7] 输出&#xff1a;[[3],[9,…...

【fabric.js】toDataURL 性能问题、优化

必要解释&#xff1a;最好看完。。省流版的话&#xff0c;toDataURL 的 multiplier参数不要设置超过500&#xff1b; 情景&#xff1a;在做某些功能的时候涉及到图形的预览&#xff0c;预览的时候是导出为40*40 像素的图片&#xff0c;当碰到某些图形非常小的时候&#xff0c;…...

基于Grafana+Prometheus搭建可视化监控系统实践

基本介绍 Grafana&#xff1a;一个监控仪表系统&#xff0c;可以根据提供的监控数据&#xff0c;生产可视化仪表盘&#xff0c;同时也具有告警通知功能。这里的监控数据来源&#xff0c;目前主要以Prometheus为主&#xff08;也支持其它数据源&#xff09;&#xff0c;每次展现…...

选择排序(堆排序和topK问题)

选择排序 每一次从待排序的数据元素中选出最小&#xff08;或最大&#xff09;的一个元素&#xff0c;存放在序列的起始位置&#xff0c;直到全部待排序的数据元素排完 。 如果我们用扑克牌来举例&#xff0c;那么选择排序就像是提前已经把所有牌都摸完了&#xff0c;而再进行牌…...

webpack tree shaking 摇树原理

Tree-shaking 是指在打包过程中通过静态分析&#xff0c;识别并删除未使用的代码&#xff0c;以减小最终输出文件的大小。Webpack 通过内置的 UglifyJS 插件或者 Terser 插件来实现 Tree-shaking。下面是简要的 webpack Tree-shaking 的原理&#xff1a; 标记未使用的代码&…...

开源模型应用落地-业务整合篇(三)

一、前言 在之前的两篇文章中,我们学习了如何构建基本的即时消息(IM)功能。今天,我们将进一步将IM模块与AI服务进行连接,实现用户提问并由模型进行回答,最后将结果展示在用户界面上。 二、术语 2.1. Spring Boot 是一个用于快速构建基于Spring框架的Java应用程序的开源框…...

js打地鼠

文章目录 1实现效果2代码实现 1实现效果 游戏难度&#xff1a;简单&#xff0c;一般&#xff0c;困难&#xff0c;噩梦&#xff08;控制setInterval的time参数&#xff09; 按钮功能&#xff1a;结束&#xff08;可以通过修改gameScore的值来修改判定结束的分数&#xff09;&am…...

计算机网络体系架构认知--网络协议栈

文章目录 一.计算机网络分层架构各协议层和计算机系统的联系从整体上理解计算机网络通信计算机网络通信的本质 二.Mac地址,IP地址和进程端口号三.局域网通信与跨局域网通信局域网通信跨局域网通信全球互联的通信脉络 四.网络编程概述 一.计算机网络分层架构 实现计算机长距离网…...

Ubuntu 22.04 安装tomcat

tomcat是常用的Java服务容器,这篇文章我们就来讲讲如何安装它。 更新软件包 首先是更新软件包,这是最常规的操作 sudo apt update 然后是开始安装,不多一会就可以安装好了 sudo apt install tomcat9 然后看一下状态 sudo systemctl status tomcat9 发现虽然启动了,但…...

记录:Ubuntu 18.04 X86 上通过CMake 指定编译器工具链交叉编译。

最好是通过 cmake 命令行来设置&#xff0c;要不然你只有在 CMakeFiles.txt 里面自己写判断语句了。 要用 cmake 交叉编译&#xff0c;必须设置连接器&#xff0c;要不然会使用当前系统的 ld&#xff0c;就是 /usr/bin/ld。 但是其它平台是不会ld上的&#xff0c;elf格式都不…...

requests,js逆向练习

自上而下排除jquery源码&#xff0c;点进去utils 发现第一次请求是getTime 再次运行此断点才是登录&#xff0c;这个时候密码已经被加密了 查看上级js页面&#xff0c;发现加密函数 进去看函数加密过程 得到结果RSA python代码 import base64 import jsonimport requests f…...

Chrome 插件调试

http://blog.haoji.me/chrome-plugin-develop.html#te-bie-zhu-yi-background-de-bao-cuo 手把手&#xff1a;Chrome浏览器开发系列(四)&#xff1a;调试我们开发的插件 - 掘金...

云轴科技ZStack成为交通运输业上云用云推进中心首批成员单位

近日&#xff0c;中国信息通信研究院、中国交通运输协会信息专业委员会联合发起成立“交通运输业上云用云推进中心”&#xff0c;上海云轴信息科技有限公司&#xff08;简称云轴科技ZStack&#xff09;凭借优秀的产品技术创新能力和在交通运输领域的实践经验成为首批成员单位并…...

代码随想录算法训练营31期day4,力扣24+19+02.07+142

24&#xff0c;动指针 class Solution { public:ListNode* swapPairs(ListNode* head) {//建立虚拟头结点auto dummynew ListNode(-1);dummy->nexthead;for(auto pdummy;p->next&&p->next->next;){auto ap->next;auto ba->next;p->nextb;a->n…...

广州地铁2号线/seo短视频网页入口

详见&#xff1a;http://blog.yemou.net/article/query/info/tytfjhfascvhzxcyt205 利用Java反射机制你可以在运行期动态的创建接口的实现。java.lang.reflect.Proxy类就可以实现这一功能。这个类的名字&#xff08;译者注&#xff1a;Proxy意思为代理&#xff09;就是为什么把…...

安徽省招标投标信息网/百度推广优化方案

你知道吗&#xff0c;一辆自动驾驶汽车每天生成的数据量达到4TB&#xff0c;而一个人每天最多生成1.5GB的数据。这一数据量级上的差距说明什么&#xff1f;今天的世界&#xff0c;人工智能、5G连接、物联网等正成为驱动业务发展和创新的原动力。 英特尔预测&#xff0c;数据中心…...

wordpress增加开场动画/销售技巧和话术

我在这里把编程语言分四类来讲述它们的差异&#xff08;为什么只分四类&#xff0c;因为我这里是砖&#xff0c;要等你的玉来补充不是吗&#xff09;。 第一类&#xff0c;单进程解释语言 python, ruby, node.js等 这类解释语言通常提供极高的开发效率&#xff0c;和相对较差的…...

大连 模板网站/百度小说排行榜2020

一、Mosaic data augmentation Mosaic数据增强方法是YOLOV4论文中提出来的&#xff0c;主要思想是将四张图片进行随机裁剪&#xff0c;再拼接到一张图上作为训练数据。 这样做有以下几个优点&#xff1a; 1、增加了数据的多样性&#xff0c;丰富了图片的背景。 2、增加了目标个…...

资阳优化团队资讯/镇江seo

概述 继承是指这样一种能力&#xff1a; 通过继承创建的新类可以使用现有类的所有功能&#xff0c;并在无需重新编写原来的类的情况下对这些功能进行扩展。 继承就是一个从一般到特殊的过程&#xff0c;是面向对象编程&#xff08;OOP&#xff09;语言的主要特征。一个子类可…...

苏省住房和城乡建设厅网站首页/宠物美容师宠物美容培训学校

为什么刷开发版&#xff0c;想必太多的小伙伴是为了root&#xff0c;ROOT虽然会让我们的手机变的并不安全&#xff0c;但是刷入开发版还是必要的&#xff0c;今天ROM乐园小编就教大家如何刷入小米CC9和小米CC9美图版MIUI开发版&#xff0c;获取ROOT权限小米玩机第一步解锁BL&am…...