当前位置: 首页 > Web前端 > HTML5

React与虚拟DOM

时间:2023-04-05 01:16:24 HTML5

虚拟DOM的概念,相信接触过React或者Vue的同学一定不陌生,但是在实际开发中,在和一些同学讨论问题的时候,发现virtual的作用DOM和React对渲染过程的理解有些偏颇。这里也给自己提个醒。要解释VirtualDOM,我们还得从JSX说起。什么是JSX?如果你想谈论React,你一定不能绕开JSX。JSX是React的灵魂。那么什么是JSX?它是一个组件吗?那是什么成分?其实官网已经明确说明JSX只是一层语法糖,比如下面的JSX代码:ClickMe编译后会变成:React.createElement(MyButton,{color:'blue',shadowSize:2},'ClickMe')复杂一点的话:

你好,这是React
马上开始学习吧!
权利保留。
编译后:React.createElement('div',{className:'cn'},React.createElement(Header,null,'Hello,ThisisReact'),React.createElement('div',null,'Starttolearnrightnow!'),'RightReserve')如果你想测试一些特定的JSX转换成什么JavaScript,你可以试试使用在线Babel编译器。代码中也找到了对应的位置,官网上也有提到。我们可以看到createElement方法只有三个入参,也就是刚才编译的三个入参。最终将返回一个名为ReactElement的对象。functioncreateElement(type,config,children){varpropName;//提取保留名称varprops={};变量键=空;变种参考=空;变种自我=空;变量源=空;...returnReactElement(type,key,ref,self,source,ReactCurrentOwner.current,props);}让我们来看看ReactElement是什么。varReactElement=function(type,key,ref,self,source,owner,props){varelement={//这个标签允许我们将其唯一标识为React元素$$typeof:REACT_ELEMENT_TYPE,//内置属性thatbelongontheelementtype:type,key:key,ref:ref,props:props,//记录负责创建这个元素的组件。_owner:所有者};...返回元素;};是一个对象,而JSX最终成为一个对象?是的!但是在Render函数中,不仅会返回ReactElement,还会返回一些其他的东西,主要有以下几类:React元素。通常通过JSX创建。例如,
会被React渲染为DOM节点,会被React渲染为自定义组件,
都是React元素。数组或片段。让render方法返回多个元素,其实就是我们平时用的<>/>。有关详细信息,请参阅片段文档。门户网站。可以将子节点渲染到不同的DOM子树中。有关更多详细信息,请参阅门户的文档字符串或数字类型。它们在DOM中呈现为文本节点。布尔值或空值。没有渲染。(主要用于支持返回test&&的模式,其中test是一个Boolean类型。)官网上也有说明:说完ReactElementforthevirtualDOMtree,再说说virtualDOM。虚拟DOM树实际上是DOM树的一个映射。通过虚拟DOM树,React可以还原一个完整的DOM树,DOM树也可以使用虚拟DOM树来保存它的结构。有点像序列化和反序列化的关系。虚拟DOM节点主要有以下几种:ReactDOMTextComponent:用于负责text节点对应的虚拟DOMReactDOMComponent:用于负责html标签对应的虚拟DOMReactEmptyComponent:用于负责null的虚拟DOM而falseReactCompositeComponent:用于负责继承对应的React.ComponentVirtualDOM,即自定义组件。这些类型涵盖了Render函数中返回的类型,React元素,数组或者Fragments,Portals,最后会解析为ReactDOMComponent,字符串和数组类型,最后会解析为ReactDOMTextComponent,boolean类型或者null最后会解析为反应空组件。也就是说,我们编写和使用的JSX或者组件,最终会一个一个的变成虚拟DOM,组合起来,最后变成一棵虚拟DOM树。也就是我们常说的虚拟DOM树。那么什么是虚拟DOM节点呢?其实也是一个JS对象,里面包含了一堆属性,还有一些渲染相关的方法,比如挂载、更新等。我们来看看15.0.0的代码:为什么要使用虚拟DOM?为什么要使用虚拟DOM的问题要从React的开发模式说起。看完这篇文章,我想在座的各位应该都知道React是一个非常典型的MVVM设计。当需要更新数据时,开发者只需要通过setState直接将数据插入到React中即可,完全不用考虑数据的渲染。在此之前,传统的web前端开发可能还是使用JQ或者手动更新界面数据。该过程繁琐且容易出错,操作不当可能会导致性能问题。数据一给,就完了。就像自己做饭一样,需要买菜、洗菜、切菜、做饭、洗碗。如果使用MVVM框架,就像叫外卖一样。只需下单,等待外卖送达,吃完饭不用洗碗,多幸福啊。但静谧的时光背后一定有人为你背负重担。这个人就是React的渲染机制,其中最重要的一个就是虚拟DOM。React几乎所有的工作都是基于虚拟DOM来完成的。那么虚拟DOM有什么用呢?最重要的作用是提高性能。事实上,就像Android的视图渲染一样,操作DOM也是一个比较耗费性能的操作。如果频繁触发,会导致性能问题,界面会卡顿。虚拟DOM的存在是为了尽量减少对DOM的操作,从而提高性能。这一步是如何实现的?回到刚刚提到的虚拟DOM节点,当React触发更新时,会依次调用Render函数,返回每一个虚拟DOM节点,最后组装出新的虚拟DOM树,然后沿着旧的虚拟DOM树。比较得到需要更新的部分,然后将这部分更新到DOM中。与性能相关的关键点有两个,一个是批处理,一个是Diff算法。批处理:在React中,并不是每个setState都会触发更新。可能会合成多个setState,最后触发update。这对于性能优化非常关键。官网也有说明:Diff算法:当触发更新逻辑时,会生成新的DOM树,对比新旧DOM树,找出差异。我们知道完全比较两棵树的性能是很差的。即使是最优算法的时间复杂度也是O(n^3),太慢了。React中使用的Diff算法并没有完全比较两棵树之间的差异。如果原节点位置的类型发生变化,则直接替换子树。另外,key是用来告诉React元素位置发生变化的。更详细的规则可以查看官网的说明。这套Diff算法将时间复杂度从O(n^3)降低到O(n),低了一个数量级。有些误会叫Render,DOM更新了?有的同学看到Render函数被调用,还以为是组件更新了,重新渲染了。其实这个过程只是生成一个新的虚拟DOM树,还没有到渲染DOM的步骤。虚拟DOM牛皮,最快?有同学看到虚拟DOM的机制,觉得很牛逼,甚至觉得比native操作还快。借用知乎的回答:没有框架可以比纯手动优化更快地优化DOM操作,因为框架的DOM操作层需要处理上层API可能产生的任何操作,其实现必须是通用的。对于任何基准测试,我都可以编写比任何框架都更快的手动优化,但这有什么意义呢?在构建实际应用的时候,是否每个地方都进行手动优化?出于可维护性的原因,这显然是不可能的。最后,逛完知乎,大家好像都在说现在Web前端的趋势是独立状态框架+多线程渲染和函数式编程。其实React16引入的函数式组件+Hook不就是这种趋势的实现吗?还有更多的东西要学。.....本文由博客多发平台OpenWrite发布!