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

聊一聊 Vue3 响应式


在 Vue3 的众多革新中,响应式原理的升级堪称关键一环。它抛弃了 Vue2 基于Object.defineProperty的数据劫持方式,转而采用 ES6 的Proxy对象,为数据响应式带来了更强大、更灵活的实现,深刻影响着 Vue3 应用的性能与开发体验。接下来,我们将深入探究 Vue3 响应式原理的底层逻辑与运行机制。

一、Proxy 的基本概念与特性

Proxy是 ES6 引入的用于创建对象代理的原生构造函数,它能够拦截并自定义对象的基本操作,比如属性的读取(get)、设置(set)、函数调用、属性删除等。通过Proxy,开发者可以在不修改原始对象的情况下,对对象的操作进行自定义处理。其基本语法如下:

<script setup>
const target = {message: 'Hello, Proxy!'
}const handler = {get(target, key) {console.log(`读取属性 ${key}`)return target[key]},set(target, key, value) {console.log(`设置属性 ${key} 为 ${value}`)target[key] = valuereturn true}
}const proxy = new Proxy(target, handler)console.log(proxy.message)proxy.message = 'Changed!'
</script>

在上述代码中,target是被代理的原始对象,handler定义了拦截行为,proxy则是创建好的代理对象。通过操作proxy,所有对对象属性的读写操作都会经过handler的处理,从而实现对对象操作的监控与干预 。

二、Vue3 中响应式的创建与实现

(一)reactive 函数

Vue3 中,reactive函数是创建响应式对象的核心方法之一,它接收一个普通对象,返回一个经过Proxy代理的响应式对象。其内部实现大致如下(简化版):

 
<script setup>
function reactive(target) {if (typeof target !== 'object' || target === null) {return target}const handler = {get(target, key) {// 依赖收集逻辑,记录哪些地方使用了该属性track(target, key)return Reflect.get(target, key)},set(target, key, value) {const oldValue = target[key]const result = Reflect.set(target, key, value)if (oldValue !== value) {// 触发更新逻辑,通知所有依赖该属性的地方进行更新trigger(target, key)}return result}}return new Proxy(target, handler)
}
function reactive(target) {if (typeof target !== 'object' || target === null) {return target}const handler = {get(target, key) {// 依赖收集逻辑,记录哪些地方使用了该属性track(target, key)return Reflect.get(target, key)},set(target, key, value) {const oldValue = target[key]const result = Reflect.set(target, key, value)if (oldValue !== value) {// 触发更新逻辑,通知所有依赖该属性的地方进行更新trigger(target, key)}return result}}return new Proxy(target, handler)
}
</script>

在get拦截器中,通过track函数进行依赖收集,记录哪些组件或计算属性依赖了当前属性;在set拦截器中,当属性值发生变化时,通过trigger函数触发依赖该属性的组件或计算属性进行更新。

(二)ref 函数

ref函数用于创建一个响应式的引用,它可以将基本数据类型(如string、number、boolean)转换为响应式数据。ref返回一个包含value属性的对象,通过操作value属性来实现数据的响应式更新。其实现原理同样基于Proxy,只不过对基本数据类型进行了一层包装:

 
<script setup>
function ref(value) {const wrapper = {value}const handler = {get(target, key) {if (key === 'value') {track(wrapper, 'value')}return Reflect.get(target, key)},set(target, key, newValue) {if (key === 'value' && target.value !== newValue) {target.value = newValuetrigger(wrapper, 'value')return true}return Reflect.set(target, key, newValue)}}return new Proxy(wrapper, handler)
}
</script>

例如,使用ref创建一个响应式的计数器:

<script setup>
import { ref } from 'vue';const count = ref(0);function increment() {count.value++;}
</script>

当count.value发生变化时,依赖count的组件会自动重新渲染。

三、依赖收集与触发更新机制

(一)依赖收集(track)

依赖收集是响应式系统的关键环节,它的作用是记录哪些地方使用了响应式数据,以便在数据变化时能够通知到对应的地方进行更新。在 Vue3 中,依赖收集主要通过track函数实现。track函数会在响应式对象的属性被读取时调用,它维护了一个全局的依赖关系图,将组件或计算属性与被访问的属性关联起来。

 
<script setup>
const targetMap = new WeakMap()
function track(target, key) {let depsMap = targetMap.get(target)if (!depsMap) {targetMap.set(target, (depsMap = new Map()))}let dep = depsMap.get(key)if (!dep) {depsMap.set(key, (dep = new Set()))}// 假设当前正在执行的组件或计算属性存储在activeEffect中dep.add(activeEffect)
}
</script>

(二)触发更新(trigger)

当响应式对象的属性值发生变化时,trigger函数会被调用,它遍历之前收集到的依赖关系,通知所有依赖该属性的组件或计算属性进行更新。

 
<script setup>
const targetMap = new WeakMap()
function track(target, key) {let depsMap = targetMap.get(target)if (!depsMap) {targetMap.set(target, (depsMap = new Map()))}let dep = depsMap.get(key)if (!dep) {depsMap.set(key, (dep = new Set()))}// 假设当前正在执行的组件或计算属性存储在activeEffect中dep.add(activeEffect)
}
</script>

这里的effect通常是组件的渲染函数或者计算属性的求值函数,当effect被调用时,会重新执行相关逻辑,实现视图的更新或计算属性的重新计算。

四、Vue3 响应式原理的优势

(一)更全面的响应式检测

相比 Vue2 中Object.defineProperty无法检测对象属性添加和删除的问题,Vue3 的Proxy可以直接拦截这些操作,自动实现响应式更新。例如,在 Vue3 中动态添加属性依然能触发视图更新:

 
<script setup>
const state = reactive({})const app = {template: `<div>{{state.message}}</div>`,setup() {setTimeout(() => {state.message = 'New message'}, 1000)return { state }}
}
</script>

(二)性能提升

Proxy是对整个对象进行代理,避免了 Vue2 中对深层对象递归劫持带来的性能开销。同时,Vue3 采用了更高效的依赖收集和更新策略,减少了不必要的重新渲染,提高了应用的性能。

(三)更好的 TypeScript 支持

Proxy的静态类型更容易推导,这使得 Vue3 在使用 TypeScript 开发时,能够提供更准确的类型提示和检查,提升了开发体验和代码的健壮性。

Vue3 响应式原理基于Proxy的创新实现,从根本上解决了 Vue2 响应式系统的局限性,为开发者带来了更强大、高效和灵活的开发体验。深入理解其原理,有助于开发者更好地优化 Vue3 应用,充分发挥框架的优势。

http://www.xdnf.cn/news/300583.html

相关文章:

  • 计算机的发展历程
  • 9-4 USART串口数据包
  • Elasticsearch知识汇总之ElasticSearch与OpenSearch比较
  • 网工实验——静态路由与BFD联动
  • 前端流行框架Vue3教程:14. 组件传递Props效验
  • 针对面试-redis篇
  • 使用Homebrew下载配置git和连接GitHub(Mac版)
  • LeetCode LCR 033. 字母异位词分组
  • springboot微服务连接nacos超时
  • CTF-DAY8
  • unordered_map和unordered_set的设计
  • OpenGl实战笔记(3)基于qt5.15.2+mingw64+opengl实现光照变化效果
  • 高性能网络优化:深入解析忙轮询(Busy Polling)技术
  • 如何把阿里云a账号下面的oss迁移到阿里云b账号下面(同区域)
  • Nginx 安全防护与 HTTPS 部署
  • UE5 把翅膀动画额外创建动画蓝图并和角色绑定混合动画
  • Kali:利用rockyou文本字典hash破解zip压缩包密码
  • MySQL + Qwen3-0.5B + Flask + Dify 工作流部署指南
  • 探秘数据中台:五大核心平台的功能全景解析
  • QuecPython+Aws:快速连接亚马逊 IoT 平台
  • 从试错到智能决策:Python与强化学习优化自动驾驶策略
  • Netty 的 Reactor 模型
  • deeplabv3+街景图片语义分割,无需训练模型,看不懂也没有影响,直接使用,cityscapes数据集_23
  • 掌握 Git 常用命令,高效管理项目版本
  • java安全入门
  • Kotlin空安全解决Android NPE问题
  • 第八章--图
  • LeetCode 3423. 循环数组中相邻元素的最大差值 题解
  • homebrew安装配置Python(MAC版)
  • Oracle01-入门