热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

React学习--React源码(2)VirtualDOM模型

VirtualDOM模型负责VirtualDOM底层框架的创建工作,它拥有整套的VirtualDOM标签,并负责虚拟节点的创建、更新、删除等工作。下面是一个简易的VirtualDOM模

VirtualDOM模型负责VirtualDOM底层框架的创建工作,它拥有整套的VirtualDOM标签,并负责虚拟节点的创建、更新、删除等工作。

下面是一个简易的VirtualDOM模型,它并不复杂,只需要具备:

标签名
节点属性:样式,属性,事件等
子节点
标识ID

{
tagName: 'div',
properties: {
style: {
}
},
children: [],
key: 1
}

virtual DOM中的节点称为ReactNode,分为:ReactElement、ReactFragment、ReactText。其中ReactElement又分为ReactComponentElement和ReactDOMElement。

通过方法createElement创建React虚拟元素

通过JSX创建的虚拟元素最终都会被编译成调用React的createElement方法。

在createElement方法中,对参数做了简单的参数修正(例如,提取config内容,处理children等),然后根据修正过的参数,返回了一个ReactElement对象。

初始化组件入口

当使用React创建组件时,首先会调用instantiateReactComponent,则是初始化组件的入口函数。该函数会根据node类型,区分不同组件的入口。

当node为空时,说明node不存在,则初始化空组件:ReactEmptyComponent.create(instan- tiateReactComponent)
当node类型为对象时,即是DOM标签或自定义组件。初始化DOM标签组件使用方法:ReactNativeComponent.createInternalComponent (element),初始化自定义组件使用方法:ReactCompositeComponentWrapper()。
当node类型为字符串或者数字,则初始化文本组件:ReactNativeComponent.create InstanceForText(node)
如果是其他情况,则不做任何处理。

以下是instantiateReactComponent方法源码:

function instantiateReactComponent(node, parentCompositeType) {
var instance;
//空组件(ReactEmptyComponent)
if (node === null || node === false) {
instance = ReactEmptyComponent.create(instantiateReactComponent);
}
if (typeof node === 'object') {
var element = node;
if (typeof element.type === 'string') {
// DOM标签(ReactDOMComponent)
instance = ReactNativeComponent.createInternalComponent(element);
} else if (isInternalComponentType(element.type)) {
// 不是字符串表示的自定义组件暂时无法使用
instance = new element.type(element);
} else {
// 自定义组件(ReactCompositeComponent)
instance = new ReactCompositeComponentWrapper();
}
} else if (typeof node === 'string' || typeof node === 'number') {
// 字符串或数字(ReactTextComponent)
instance = ReactNativeComponent.createInstanceForText(node);
} else {
// 不做处理
}
// 设置实例
instance.construct(node);
// 初始化参数
instance._mountIndex = 0;
instance._mountImage = null;

return instance;
}

这里写图片描述

关于组件是什么的问题:
这里的组件就是我们在使用react编程时,采用class方法或者直接用函数方法声明的React组件,所有这些组件都最终会被解释为VirtualDOM元素。

文本组件 ##

当node节点为文本节点是,是不算VirtualDOM元素的,但是React为了保持渲染的一致性,将其封装为文本组件:ReactDOMTextComponent。

在执行mountComponent方法时,ReactDOMTextComponent通过transaction.useCreateElement判断该文本是否是通过createElement方法创建的节点,如果是,则为该节点创建相应的标签和标识符。如果不是,React将直接返回文本内容。

DOM标签组件

当开发者在React中使用DOM标签时,例如div,此时的div并不是原生div,其实是React生成的VirtualDOM对象。React的大部分工作都是在VirtualDOM中完成的,这些工作并不会直接操作和污染原生的DOM。这样在性能方面能大有改进,并且降低了直接操作DOM而导致错误的风险。

ReactDOMComponent 对于 Virtual DOM 标签的处理主要包括了两个部分:
1、属性的更新:样式、属性、事件等。
2、子节点的更新:子节点内容、子节点自身、此部分设计diff算法。

1、更新属性

当执行mountComponent方法时,ReactDOMComponent首先会生成标记和标签,通过方法:this. createOpenTagMarkupAndPutListeners(transaction) 来处理DOM节点的属性和事件。

1、如果存在事件,则针对当前的节点添加事件代理:enqueuePutListener(this, propKey, propValue, transaction)
2、如果存在样式,首先会对样式进行合并操作,然后通过CSSPropertyOperations.createMarkupForStyles(propValue, this)方法创建样式。
3、创建属性:DOMPropertyOperations.createMarkupForProperty(propKey, propValue)
4、创建唯一标识符:DOMPropertyOperations.createMarkupForID(this._domID)

当执行receiveComponent方法时,ReactDOMComponent会通过this.updateComponent来更新DOM节点属性(真实DOM)。进行了如下两方面的工作:
1、删除不需要的旧属性
2、更新新属性

2、更新子节点

当执行mountComponent方法时,ReactDOMComponent会通过方法this._createContentMarkup (transaction, props, context)来处理DOM节点的内容。首先获取节点内容,如果节点存在子节点,则通过方法this. mountChildren(childrenToUse, transaction, context)对子节点进行初始化渲染。

和更新属性类似,当执行receiveComponent方法时,ReactDOMComponent会通过this._updateDOMChildren
(lastProps, nextProps, transaction, context)来更新DOM内容和子节点(真实DOM)。进行了如下两方面的工作:
1、删除不需要的子节点和内容
2、更新子节点和内容

自定义组件

自定义组件ReactCompositeComponent实现了一整套的React生命周期和setState机制,因此自定义组件实在生命周期环境中进行更新属性、内容和子节点的操作。这些更新操作与ReactDOMComponent的操作类似。


推荐阅读
  • 如何自行分析定位SAP BSP错误
    The“BSPtag”Imentionedintheblogtitlemeansforexamplethetagchtmlb:configCelleratorbelowwhichi ... [详细]
  • 本文介绍了lua语言中闭包的特性及其在模式匹配、日期处理、编译和模块化等方面的应用。lua中的闭包是严格遵循词法定界的第一类值,函数可以作为变量自由传递,也可以作为参数传递给其他函数。这些特性使得lua语言具有极大的灵活性,为程序开发带来了便利。 ... [详细]
  • 1,关于死锁的理解死锁,我们可以简单的理解为是两个线程同时使用同一资源,两个线程又得不到相应的资源而造成永无相互等待的情况。 2,模拟死锁背景介绍:我们创建一个朋友 ... [详细]
  • JVM 学习总结(三)——对象存活判定算法的两种实现
    本文介绍了垃圾收集器在回收堆内存前确定对象存活的两种算法:引用计数算法和可达性分析算法。引用计数算法通过计数器判定对象是否存活,虽然简单高效,但无法解决循环引用的问题;可达性分析算法通过判断对象是否可达来确定存活对象,是主流的Java虚拟机内存管理算法。 ... [详细]
  • Python正则表达式学习记录及常用方法
    本文记录了学习Python正则表达式的过程,介绍了re模块的常用方法re.search,并解释了rawstring的作用。正则表达式是一种方便检查字符串匹配模式的工具,通过本文的学习可以掌握Python中使用正则表达式的基本方法。 ... [详细]
  • Html5-Canvas实现简易的抽奖转盘效果
    本文介绍了如何使用Html5和Canvas标签来实现简易的抽奖转盘效果,同时使用了jQueryRotate.js旋转插件。文章中给出了主要的html和css代码,并展示了实现的基本效果。 ... [详细]
  • 本文讨论了一个数列求和问题,该数列按照一定规律生成。通过观察数列的规律,我们可以得出求解该问题的算法。具体算法为计算前n项i*f[i]的和,其中f[i]表示数列中有i个数字。根据参考的思路,我们可以将算法的时间复杂度控制在O(n),即计算到5e5即可满足1e9的要求。 ... [详细]
  • vue使用
    关键词: ... [详细]
  • PHP图片截取方法及应用实例
    本文介绍了使用PHP动态切割JPEG图片的方法,并提供了应用实例,包括截取视频图、提取文章内容中的图片地址、裁切图片等问题。详细介绍了相关的PHP函数和参数的使用,以及图片切割的具体步骤。同时,还提供了一些注意事项和优化建议。通过本文的学习,读者可以掌握PHP图片截取的技巧,实现自己的需求。 ... [详细]
  • 开发笔记:加密&json&StringIO模块&BytesIO模块
    篇首语:本文由编程笔记#小编为大家整理,主要介绍了加密&json&StringIO模块&BytesIO模块相关的知识,希望对你有一定的参考价值。一、加密加密 ... [详细]
  • HDU 2372 El Dorado(DP)的最长上升子序列长度求解方法
    本文介绍了解决HDU 2372 El Dorado问题的一种动态规划方法,通过循环k的方式求解最长上升子序列的长度。具体实现过程包括初始化dp数组、读取数列、计算最长上升子序列长度等步骤。 ... [详细]
  • 如何使用Java获取服务器硬件信息和磁盘负载率
    本文介绍了使用Java编程语言获取服务器硬件信息和磁盘负载率的方法。首先在远程服务器上搭建一个支持服务端语言的HTTP服务,并获取服务器的磁盘信息,并将结果输出。然后在本地使用JS编写一个AJAX脚本,远程请求服务端的程序,得到结果并展示给用户。其中还介绍了如何提取硬盘序列号的方法。 ... [详细]
  • 个人学习使用:谨慎参考1Client类importcom.thoughtworks.gauge.Step;importcom.thoughtworks.gauge.T ... [详细]
  • 高质量SQL书写的30条建议
    本文提供了30条关于优化SQL的建议,包括避免使用select *,使用具体字段,以及使用limit 1等。这些建议是基于实际开发经验总结出来的,旨在帮助读者优化SQL查询。 ... [详细]
  • 重入锁(ReentrantLock)学习及实现原理
    本文介绍了重入锁(ReentrantLock)的学习及实现原理。在学习synchronized的基础上,重入锁提供了更多的灵活性和功能。文章详细介绍了重入锁的特性、使用方法和实现原理,并提供了类图和测试代码供读者参考。重入锁支持重入和公平与非公平两种实现方式,通过对比和分析,读者可以更好地理解和应用重入锁。 ... [详细]
author-avatar
少爷自控_592
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有