当前位置: 首页 > 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;而再进行牌…...

springboot 百货中心供应链管理系统小程序

一、前言 随着我国经济迅速发展&#xff0c;人们对手机的需求越来越大&#xff0c;各种手机软件也都在被广泛应用&#xff0c;但是对于手机进行数据信息管理&#xff0c;对于手机的各种软件也是备受用户的喜爱&#xff0c;百货中心供应链管理系统被用户普遍使用&#xff0c;为方…...

CMake基础:构建流程详解

目录 1.CMake构建过程的基本流程 2.CMake构建的具体步骤 2.1.创建构建目录 2.2.使用 CMake 生成构建文件 2.3.编译和构建 2.4.清理构建文件 2.5.重新配置和构建 3.跨平台构建示例 4.工具链与交叉编译 5.CMake构建后的项目结构解析 5.1.CMake构建后的目录结构 5.2.构…...

el-switch文字内置

el-switch文字内置 效果 vue <div style"color:#ffffff;font-size:14px;float:left;margin-bottom:5px;margin-right:5px;">自动加载</div> <el-switch v-model"value" active-color"#3E99FB" inactive-color"#DCDFE6"…...

R语言速释制剂QBD解决方案之三

本文是《Quality by Design for ANDAs: An Example for Immediate-Release Dosage Forms》第一个处方的R语言解决方案。 第一个处方研究评估原料药粒径分布、MCC/Lactose比例、崩解剂用量对制剂CQAs的影响。 第二处方研究用于理解颗粒外加硬脂酸镁和滑石粉对片剂质量和可生产…...

作为测试我们应该关注redis哪些方面

1、功能测试 数据结构操作&#xff1a;验证字符串、列表、哈希、集合和有序的基本操作是否正确 持久化&#xff1a;测试aof和aof持久化机制&#xff0c;确保数据在开启后正确恢复。 事务&#xff1a;检查事务的原子性和回滚机制。 发布订阅&#xff1a;确保消息正确传递。 2、性…...

Java 与 MySQL 性能优化:MySQL 慢 SQL 诊断与分析方法详解

文章目录 一、开启慢查询日志&#xff0c;定位耗时SQL1.1 查看慢查询日志是否开启1.2 临时开启慢查询日志1.3 永久开启慢查询日志1.4 分析慢查询日志 二、使用EXPLAIN分析SQL执行计划2.1 EXPLAIN的基本使用2.2 EXPLAIN分析案例2.3 根据EXPLAIN结果优化SQL 三、使用SHOW PROFILE…...

CppCon 2015 学习:Time Programming Fundamentals

Civil Time 公历时间 特点&#xff1a; 共 6 个字段&#xff1a; Year&#xff08;年&#xff09;Month&#xff08;月&#xff09;Day&#xff08;日&#xff09;Hour&#xff08;小时&#xff09;Minute&#xff08;分钟&#xff09;Second&#xff08;秒&#xff09; 表示…...

EC2安装WebRTC sdk-c环境、构建、编译

1、登录新的ec2实例&#xff0c;证书可以跟之前的实例用一个&#xff1a; ssh -v -i ~/Documents/cert/qa.pem ec2-user70.xxx.165.xxx 2、按照sdk-c demo中readme的描述开始安装环境&#xff1a; https://github.com/awslabs/amazon-kinesis-video-streams-webrtc-sdk-c 2…...

MAZANOKE结合内网穿透技术实现跨地域图像优化服务的远程访问过程

文章目录 前言1. 关于MAZANOKE2. Docker部署3. 简单使用MAZANOKE4. 安装cpolar内网穿透5. 配置公网地址6. 配置固定公网地址总结 前言 在数字世界高速发展的今天&#xff0c;您是否察觉到那些静默增长的视觉数据正在悄然蚕食存储空间&#xff1f;随着影像记录成为日常习惯&…...

【Redis】Redis 的持久化策略

目录 一、RDB 定期备份 1.2 触发方式 1.2.1 手动触发 1.2.2.1 自动触发 RDB 持久化机制的场景 1.2.2.2 检查是否触发 1.2.2.3 线上运维配置 1.3 检索工具 1.4 RDB 备份实现原理 1.5 禁用 RDB 快照 1.6 RDB 优缺点分析 二、AOF 实时备份 2.1 配置文件解析 2.2 开启…...