React、Vue框架如何实现组件更新,原理是什么?

引言

React 和 Vue 都是当今最流行的前端框架,它们都实现了组件化开发模式。为了优化性能,两者都采用了虚拟DOM技术。当组件状态发生改变时,它们会使用虚拟DOM进行局部渲染比对,只更新必要的DOM节点,从而避免重新渲染整个组件树。本文将从React和Vue的组件更新原理入手,剖析两者虚拟DOM difer算法的异同点。React通过comparing virtual DOM components and re-rendering only difference,而Vue通过响应式依赖追踪确定组件invalidated状态。尽管两者技术实现不同,但目的都是实现增量更新提高性能。本文还将通过代码实例,说明两者的Domin difer流程、对比粒度、更新触发等关键区别。读者将对React和Vue增量更新的内在原理有更深的理解,学会在实践中根据应用场景选择更合适的框架。

React、Vue如何实现组件更新

React和Vue是两个流行的JavaScript库,用于构建用户界面。它们都有自己的组件,下面将简单介绍一下更新原理。

React的组件更新机制:
在React中,组件更新是由虚拟DOM(Virtual DOM)和diff算法驱动的。当组件的状态(state)或属性(props)发生变化时,React会进行虚拟DOM的重新渲染,并将新的虚拟DOM与旧的虚拟DOM进行比较,找出需要更新的部分,然后只更新这些部分到实际的DOM。

React的组件更新流程如下:

  1. 组件状态或属性发生变化。
  2. React调用组件的render()方法重新渲染虚拟DOM。
  3. React将新的虚拟DOM与旧的虚拟DOM进行比较,找出需要更新的部分。
  4. React通过最小化DOM操作,只更新需要变化的部分到实际的DOM。
  5. 组件更新完成,触发相应的生命周期方法(如componentDidUpdate)。

下面是一个简单的React组件的例子,展示了组件的更新机制:

import React, { Component } from 'react';class Counter extends Component {constructor(props) {super(props);this.state = {count: 0};}handleClick = () => {this.setState(prevState => ({count: prevState.count + 1}));}render() {return (<div><p>Count: {this.state.count}</p><button onClick={this.handleClick}>Increment</button></div>);}
}

在上面的例子中,当用户点击"Increment"按钮时,handleClick方法会更新组件的状态count。React会重新调用render()方法重新渲染虚拟DOM,并将新的虚拟DOM与旧的虚拟DOM进行比较,然后只更新变化的部分(这里是<p>Count: {this.state.count}</p>)到实际的DOM。

Vue的组件更新机制:
在Vue中,组件更新是由响应式系统驱动的。Vue使用了一种名为"依赖追踪"的机制,它会在组件渲染过程中追踪组件所依赖的数据,并建立起依赖关系。当依赖的数据发生变化时,Vue会通知相关的组件进行更新。
Vue的更新过程大致如下:

  1. 数据变化时,setter 触发依赖,标记组件为脏数据
  2. 在下一轮事件循环中,Vue 会调用 patch 函数,比对新旧虚拟 DOM 树
  3. 通过 diff 算法比较树的差异,得到需要更新的最小节点
  4. 只对变化的部分进行 DOM 操作,更新视图
    diff 算法的主要步骤是:
  • 对比新旧节点,是否为同一节点
  • 如果不是,直接替换该节点及子节点
  • 如果是,对比新旧节点的属性是否变化
  • 对比子节点,使用键值优化顺序复杂度
  • 递归对比所有子节点
    通过这种方式,Vue 可以只更新变化的部分,避免不必要的 DOM 操作。
    下面是一个简单的Vue组件的例子,展示了组件的更新机制:
<template><div><p>Count: {{ count }}</p><button @click="increment">Increment</button></div>
</template><script>
export default {data() {return {count: 0};},methods: {increment() {this.count++;}}
}
</script>

在上面的例子中,当用户点击"Increment"按钮时,increment方法会更新组件的数据count。Vue会检测到count的变化,并通知组件重新渲染。然后Vue使用虚拟DOM进行比较,只更新变化的部分(这里是<p>Count: {{ count }}</p>)到实际的DOM。

总结:
React和Vue都采用了类似的组件更新机制,它们都通过比较虚拟DOM或追踪依赖来实现高效的组件更新。React和Vue都使用虚拟DOM和diff算法,这些机制使得组件的更新变得高效,只更新必要的部分,提高了应用的性能。

React与Vue更新的区别

Vue

  • 使用数据响应系统,通过改变组件的数据属性来触发更新。
  • 当组件的 data、props、computed 等属性改变时,会触发 setter,标记组件为“脏”。
  • 在下一轮事件循环中,会批量触发这些“脏”组件的重新渲染。

React

  • 使用状态(state)和属性(props)来控制组件。
  • 当状态或属性改变时,会触发重新渲染。
  • React 使用 Virtual DOM 来提高性能,只会针对改变的组件进行最小化渲染。
    相同点
  • 两者都是声明式框架,通过状态/数据变化控制界面。
  • 都使用虚拟 DOM ,进行增量更新提高性能。
    区别
  • Vue 侧重响应式数据,React 更侧重状态管理。
  • Vue 使用模板,React 使用 JSX。
  • Vue 批量异步更新,React 同步更新。
  • Vue 依赖数据变化触发更新,React 通过 setState/useState 控制。
    总体来说,两者都使用了类似的虚拟DOM和增量更新机制,但在触发更新的方式上有差异。Vue 更加主动,而 React 更加显式地控制。

什么是Diff算法

diff 算法是虚拟 DOM 中用于增量更新的关键算法。它的主要作用是对比两棵虚拟 DOM 树的差异,运算出需要更新的最小量 DOM 操作。
diff 算法的基本步骤如下:

  1. 用虚拟 DOM 构建出新的DOM树(树A)
  2. 将新的DOM树与旧的DOM树(树B)进行对比找出差异
  3. 对比过程中,首先比较树A和树B的根节点
  4. 如果根节点不相同,直接替换整个DOM树
  5. 如果根节点相同,再递归地对比和更新它的属性、子节点等
  6. 只更新变化的部分,不修改相同的节点
  7. 最后将变化渲染到真实DOM中
    diff算法的时间复杂度为O(n),它通过以下优化进一步提升了性能:
  • Web UI中DOM节点跨层级的移动操作特别少,可以忽略不计
  • 拥有相同类的两个组件生成相似的树形结构,拥有较高的移位率
  • 通过唯一id区分节点,可以根据id直接判断两个节点是否相同

这里是一个简化的React Diff算法的实现示例。它包含了比较根节点、属性和子节点的逻辑。当根节点类型不同时,创建新节点并替换旧节点。当属性不同时,更新属性。对于子节点,通过遍历旧子节点和新子节点来进行比较,并进行递归的Diff算法调用。根据比较结果,进行增加、删除或更新相应的节点。

// 旧的虚拟DOM树
let oldVDOM = {tag: 'div',attrs: {id: 'container' },children: [{tag: 'p', attrs: {class: 'paragraph'}},{tag: 'span', attrs: {class: 'span'}}]
}// 新的虚拟DOM树 
let newVDOM = {tag: 'div',attrs: {id: 'container'},children: [{tag: 'p', attrs: {class: 'paragraph'}},{tag: 'span', attrs: {class: 'span-new'}} // span类名变化]
}// diff算法
function diff(oldTree, newTree) {// 1. 比较根节点if(oldTree.tag !== newTree.tag) {// 根节点不同,返回新树return newTree}// 2. 比较属性if(oldTree.attrs.id !== newTree.attrs.id) {// id变化,更新属性newTree.attrs = newTree.attrs }// 3. 比较子节点constchildChanges = []// 使用key进行优化oldTree.children.forEach(child => {const newChild = newTree.children.find(c => c.key === child.key)// 深度递归对比子节点const changedChild = diff(child, newChild)childChanges.push(changedChild)})newTree.children = childChangesreturn newTree
}// 最终只会更新 span 的类名变化 
const newVDOM = diff(oldVDOM, newVDOM) 

两者的diff算法的区别

Vue 和 React 虽然都采用了虚拟 DOM 和 diff 算法,但在具体的 diff 实现上还是有一些区别的:

  1. 对比粒度不同
  • Vue 的虚拟 DOM 是Render 函数渲染生成的,对比粒度为组件级别。
  • React 的虚拟 DOM 是由 React元素构成,对比粒度为节点级别。
  1. 处理方式不同
  • Vue 通过标记静态子树,可以重复使用不变的部分。
  • React 总是重新构造虚拟 DOM,对相同节点也会进行属性对比。
  1. 组件识别不同
  • Vue 通过组件的 name 属性识别组件是否相同。
  • React 通过组件 type 来判断是否为相同组件类型。
  1. key 的作用不同
  • Vue 主要用 key 管理可复用的元素。
  • React 主要用 key 匹配旧元素与新元素。
  1. 事件处理不同
  • Vue 可以精确知道哪个事件发生变化,只更新事件。
  • React 每次都需要重新绑定事件,对组件影响较大。
    综上,Vue 和 React 虽然概念上都是通过虚拟 DOM + diff 实现增量更新,但在具体实现和优化上还是有一定区别的。

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

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

相关文章

Progressive Dual-Branch Network for Low-Light Image Enhancement 论文阅读笔记

这是22年中科院2区期刊的一篇有监督暗图增强的论文 网络结构如下图所示&#xff1a; ARM模块如下图所示&#xff1a; CAB模块如下图所示&#xff1a; LKA模块其实就是放进去了一些大卷积核&#xff1a; AFB模块如下图所示&#xff1a; 这些网络结构没什么特别的&#xf…

分布式光伏监控系统运维系统实时查看数据分布式光伏电站监控管理

光伏电站是一种利用太阳能发电的设施&#xff0c;随着人们对可再生能源的需求不断增加&#xff0c;光伏电站的建设也越来越普遍。但是&#xff0c;光伏电站的运营和管理需要高质量的监控系统来确保其正常运行。本文将介绍光伏电站监控系统的组成及其原理。 详细软件具体需求可…

冒泡排序与快速排序(交换排序)

目录 前言 一、冒泡排序 1.基本思想 2.冒泡排序&#xff1a; 3.代码实现&#xff1a; 二、快速排序 1. 概念&#xff1a; 2.三种实现&#xff1a; 3.代码实现&#xff1a; 4.优化: 前言 所谓交换&#xff0c;就是根据序列中两个记录键值的比较结果来对换这两个记录在序…

【二等奖方案】基于人工智能的漏洞数据分类赛题「道可道,非常道」团队解题思路

2022 CCF BDCI 大赛 数字安全公开赛「基于人工智能的漏洞数据分类」赛题二等奖团队「道可道&#xff0c;非常道」战队获奖方案&#xff0c;赛题地址&#xff1a; http://go.datafountain.cn/s57 团队简介 本团队具有丰富的比赛和项目经验。在AI大赛上多次拿到Top成绩&#xf…

FFMPEG源码之过滤器

功能介绍 FFmpeg的过滤器是用于对音视频流进行处理和转换的模块。它可以对输入流进行各种操作&#xff0c;如调整大小、调节亮度、对比度、裁剪、旋转等。 操作步骤 实现对某个视频的放大操作的详细步骤如下&#xff1a; 配置和初始化FFmpeg&#xff1a;在开始编写代码之前…

线性表之链表

1、链表概述 链表是一种物理存储结构上非连续、非顺序的存储结构&#xff0c;数据元素的逻辑顺序是通过链表中的指针链接次序实现的。 顺序表的存储位置可以用一个简单直观的公式表示&#xff0c;它可以随机存取表中任意一个元素&#xff0c;但插入和删除需要移动大量元素。链式…

深入理解 PostgreSQL 的架构和内部工作原理

&#x1f337;&#x1f341; 博主 libin9iOak带您 Go to New World.✨&#x1f341; &#x1f984; 个人主页——libin9iOak的博客&#x1f390; &#x1f433; 《面试题大全》 文章图文并茂&#x1f995;生动形象&#x1f996;简单易学&#xff01;欢迎大家来踩踩~&#x1f33…

Postman怎么做接口测试-以简单的登录接口为例

我们就以登录某测试系统为例子&#xff0c;实现在Postman上做接口测试 一、首先打开系统首页首页&#xff0c;做一个登录操作&#xff08;目的是获取接口url及参数&#xff09;&#xff1a;一般在公司做接口测试的时候页面还没有出来&#xff0c;我们需要根据接口文档进行接口…

kafka第三课-可视化工具、生产环境问题总结以及性能优化

一、可视化工具 https://pan.baidu.com/s/1qYifoa4 密码&#xff1a;el4o 下载解压之后&#xff0c;编辑该文件&#xff0c;修改zookeeper地址&#xff0c;也就是kafka注册的zookeeper的地址&#xff0c;如果是zookeeper集群&#xff0c;以逗号分开 vi conf/application.conf 启…

Python 逻辑回归:理论与实践

文章目录 1. 介绍1.1 什么是逻辑回归&#xff1f;1.2 逻辑回归的应用领域 2. 逻辑回归的原理2.1 Sigmoid 函数2.2 决策边界2.3 损失函数 3. 逻辑回归的实现3.1 数据准备3.2 创建逻辑回归模型3.3 模型训练3.4 模型预测3.5 模型评估 4. 可视化决策边界4.1 绘制散点图4.2 绘制决策…

基于SaaS模式的Java基层卫生健康云HIS系统源码【运维管理+运营管理+综合监管】

云HIS综合管理平台 一、模板管理 模板分为两种&#xff1a;病历模板和报表模板。模板管理是运营管理的核心组成部分&#xff0c;是基层卫生健康云中各医疗机构定制电子病历和报表的地方&#xff0c;各医疗机构可根据自身特点特色定制电子病历和报表&#xff0c;制作的电子病历…

php 手机加*星 【字符串】

场景&#xff1a;展示手机号时&#xff0c;避免暴露隐私信息&#xff0c;因此需要给手机号加*号 代码 /*** 手机号码隐私加星* param string $mobile 手机号*/ function mobileToStar(string $mobile) { // 正则检测手机号if(!preg_match(/^1[3456789]\d{9}$/,$mobile)){// …

Docker 容器生命周期:创建、启动、暂停与停止----从创建到停止多角度分析

&#x1f337;&#x1f341; 博主 libin9iOak带您 Go to New World.✨&#x1f341; &#x1f984; 个人主页——libin9iOak的博客&#x1f390; &#x1f433; 《面试题大全》 文章图文并茂&#x1f995;生动形象&#x1f996;简单易学&#xff01;欢迎大家来踩踩~&#x1f33…

Sysbench测试工具详解

文章目录 Sysbench安装准备测试数据使用yum安装的路径进行测试测试结果 Sysbench Sysbench 是一个常用的多线程性能测试工具&#xff0c;可用于评估数据库系统和硬件的性能。它支持多种基准测试&#xff0c;包括 OLTP (Online Transaction Processing)、CPU、文件 I/O、内存等。…

代码随想录| 图论04 查并集 ●查并集理论知识 ●1971.寻找图中是否存在路径 ●684.冗余连接 ●685.冗余连接II

#查并集理论知识 并查集用处&#xff1a;解决连通性问题 将两个元素添加到一个集合中。判断两个元素在不在同一个集合 思路&#xff1a;将三个元素A&#xff0c;B&#xff0c;C &#xff08;分别是数字&#xff09;放在同一个集合&#xff0c;其实就是将三个元素连通在一起&a…

Python 算法基础篇:插入排序和希尔排序

Python 算法基础篇&#xff1a;插入排序和希尔排序 引言 1. 插入排序算法概述2. 插入排序算法实现实例1&#xff1a;插入排序 3. 希尔排序算法概述4. 希尔排序算法实现实例2&#xff1a;希尔排序 5. 插入排序与希尔排序的对比总结 引言 插入排序和希尔排序是两种常用的排序算法…

017-从零搭建微服务-系统服务(四)

写在最前 如果这个项目让你有所收获&#xff0c;记得 Star 关注哦&#xff0c;这对我是非常不错的鼓励与支持。 源码地址&#xff08;后端&#xff09;&#xff1a;https://gitee.com/csps/mingyue 源码地址&#xff08;前端&#xff09;&#xff1a;https://gitee.com/csps…

【实战】 七、Hook,路由,与 URL 状态管理(下) —— React17+React Hook+TS4 最佳实践,仿 Jira 企业级项目(十三)

文章目录 一、项目起航&#xff1a;项目初始化与配置二、React 与 Hook 应用&#xff1a;实现项目列表三、TS 应用&#xff1a;JS神助攻 - 强类型四、JWT、用户认证与异步请求五、CSS 其实很简单 - 用 CSS-in-JS 添加样式六、用户体验优化 - 加载中和错误状态处理七、Hook&…

el-upload将上传的图片转为base64

el-upload将上传的图片转为base64 文章目录 el-upload将上传的图片转为base641. el-upload属性设置2. 图片转base64格式方法3. 在绑定的方法中调用 elementui使用el-upload时将选择的图片转为base64格式,然后再上传 1. el-upload属性设置 使用组件&#xff0c;然后on-change绑定…

【NLP】如何使用Hugging-Face-Pipelines?

一、说明 随着最近开发的库&#xff0c;执行深度学习分析变得更加容易。其中一个库是拥抱脸。Hugging Face 是一个平台&#xff0c;可为 NLP 任务&#xff08;如文本分类、情感分析等&#xff09;提供预先训练的语言模型。 本博客将引导您了解如何使用拥抱面部管道执行 NLP 任务…