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

Vue3响应式原理:深入理解Proxy和Ref

Vue3响应式原理:深入理解Proxy和Ref

前言

各位前端小伙伴,不知道你们有没有好奇过:Vue的响应式系统是怎么工作的?为什么数据变化会自动更新视图?

我曾经对这个问题非常好奇,后来深入研究了Vue3的源码,终于搞懂了它的实现原理!今天就来分享给大家。

Vue2 vs Vue3响应式

Vue2的Object.defineProperty

// Vue2的响应式实现 function defineReactive(obj, key, val) { Object.defineProperty(obj, key, { enumerable: true, configurable: true, get() { // 依赖收集 Dep.target && dep.addSub(Dep.target) return val }, set(newVal) { if (newVal === val) return val = newVal // 触发更新 dep.notify() } }) }

缺点

  • 无法检测对象属性的添加和删除
  • 无法检测数组元素的变化
  • 需要递归遍历对象

Vue3的Proxy

// Vue3的响应式实现 function reactive(target) { return new Proxy(target, { get(target, key, receiver) { // 依赖收集 track(target, key) const result = Reflect.get(target, key, receiver) // 递归处理嵌套对象 if (isObject(result)) { return reactive(result) } return result }, set(target, key, value, receiver) { const result = Reflect.set(target, key, value, receiver) // 触发更新 trigger(target, key) return result }, deleteProperty(target, key) { const result = Reflect.deleteProperty(target, key) // 触发更新 trigger(target, key) return result } }) }

优点

  • 可以检测对象属性的添加和删除
  • 可以检测数组元素的变化
  • 性能更好,无需递归遍历

Proxy工作原理

┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐ │ 数据对象 │ │ Proxy │ │ 副作用函数 │ └────────┬────────┘ └────────┬────────┘ └────────┬────────┘ │ │ │ │ 1. 创建Proxy代理 │ │ │───────────────────────>│ │ │ │ │ │ │ 2. 访问属性触发get │ │<───────────────────────│ │ │ │ │ │ │ │ 3. 依赖收集 │ │ │────────────────────────>│ │ │ │ │ │ 4. 修改属性触发set │ │<───────────────────────│ │ │ │ │ │ │ │ 5. 触发更新 │ │ │<────────────────────────│

ref和reactive的区别

ref的实现

class RefImpl { constructor(value) { this._value = value this._dep = new Dep() } get value() { // 依赖收集 trackRefValue(this) return this._value } set value(newVal) { if (hasChanged(newVal, this._value)) { this._value = newVal // 触发更新 triggerRefValue(this) } } } function ref(value) { return new RefImpl(value) }

reactive的实现

function reactive(target) { // 如果已经是响应式对象,直接返回 if (isReactive(target)) { return target } const proxy = new Proxy(target, { get(target, key, receiver) { // 依赖收集 track(target, key) const result = Reflect.get(target, key, receiver) // 递归处理嵌套对象 if (isObject(result) && !isReactive(result)) { return reactive(result) } return result }, set(target, key, value, receiver) { const oldValue = target[key] const result = Reflect.set(target, key, value, receiver) if (hasChanged(value, oldValue)) { // 触发更新 trigger(target, key) } return result } }) return proxy }

依赖收集和触发更新

track函数

const targetMap = new WeakMap() function track(target, key) { // 获取当前活跃的副作用函数 const effect = activeEffect if (!effect) return // 获取target对应的Map let depsMap = targetMap.get(target) if (!depsMap) { depsMap = new Map() targetMap.set(target, depsMap) } // 获取key对应的依赖集合 let dep = depsMap.get(key) if (!dep) { dep = new Set() depsMap.set(key, dep) } // 将副作用函数添加到依赖集合 if (!dep.has(effect)) { dep.add(effect) effect.deps.push(dep) } }

trigger函数

function trigger(target, key) { // 获取target对应的依赖Map const depsMap = targetMap.get(target) if (!depsMap) return // 获取key对应的依赖集合 const dep = depsMap.get(key) if (!dep) return // 执行所有依赖的副作用函数 const effects = new Set(dep) effects.forEach(effect => { effect() }) }

响应式实战

创建响应式对象

import { reactive, ref } from 'vue' // reactive用于对象 const state = reactive({ name: 'Vue', version: 3 }) // ref用于基本类型 const count = ref(0) // 修改数据会自动触发更新 state.name = 'Vue 3' count.value++

嵌套响应式

const state = reactive({ user: { name: 'John', address: { city: 'Beijing' } } }) // 嵌套对象也会被响应式处理 state.user.name = 'Jane' state.user.address.city = 'Shanghai'

数组响应式

const list = reactive([1, 2, 3]) // 数组操作也会触发更新 list.push(4) list.pop() list[0] = 100

响应式高级用法

shallowReactive

import { shallowReactive } from 'vue' const state = shallowReactive({ nested: { count: 0 } }) // 顶层属性变化会触发更新 state.nested = { count: 1 } // 嵌套属性变化不会触发更新 state.nested.count++

shallowRef

import { shallowRef } from 'vue' const state = shallowRef({ count: 0 }) // 修改引用会触发更新 state.value = { count: 1 } // 修改属性不会触发更新 state.value.count++

readonly

import { readonly } from 'vue' const state = reactive({ count: 0 }) const readOnlyState = readonly(state) // 尝试修改会警告 readOnlyState.count++ // Warning: Set operation on key "count" failed

watchEffect

import { ref, watchEffect } from 'vue' const count = ref(0) watchEffect(() => { console.log('Count changed:', count.value) }) count.value++ // 输出: Count changed: 1 count.value++ // 输出: Count changed: 2

响应式原理常见问题

问题1:为什么ref需要.value?

原因

  • JavaScript的基本类型(string、number、boolean)是值传递
  • Proxy无法代理基本类型
  • ref通过包装对象来实现响应式

问题2:为什么数组索引修改不触发更新?

解决方案

  • Vue3已经支持数组索引修改
  • 确保使用reactive创建数组

问题3:为什么对象新增属性不触发更新?

解决方案

  • Vue3使用Proxy,支持新增属性
  • 确保使用reactive创建对象

响应式性能优化

1. 使用shallowReactive优化大型对象

// 对于不需要深层响应式的大型对象 const largeObject = shallowReactive(largeData)

2. 使用ref替代reactive

// ref性能更好,因为不需要Proxy const count = ref(0) const name = ref('Vue')

3. 避免在循环中创建响应式对象

// 不好的做法 items.forEach(item => { item.data = reactive(item.data) }) // 好的做法 const data = reactive(items.map(item => item.data))

总结

Vue3的响应式系统基于Proxy实现,相比Vue2有很大改进:

  1. 更强大:支持对象属性的添加和删除
  2. 更高效:无需递归遍历
  3. 更灵活:支持多种响应式类型

现在,你应该对Vue3的响应式原理有了深入的理解!快去试试吧!

最后一句忠告:不要过度使用响应式,只在需要的地方使用!

http://www.jsqmd.com/news/853898/

相关文章:

  • 告别apt!Ubuntu 20.04下从源码编译安装ROS Noetic版UUV Simulator的保姆级教程
  • 5分钟从图片到3D模型:零基础掌握ImageToSTL图片转STL技术
  • 5元级MCU Air601实战评测:硬件兼容、LuatOS开发与ESP12F迁移指南
  • 2026 中国伺服卷板机权威实力排行榜 - 安徽工业
  • 2026 中国拼板焊设备权威实力排行榜 - 安徽工业
  • Kubernetes GitOps 实践:使用 Argo CD 实现持续部署
  • 2026 中国直缝焊机权威实力排行榜 - 安徽工业
  • 2026年餐饮酒店采购供应商推荐榜单:优质酒水供应商综合测评发布 - 资讯速览
  • 4种颠覆性组合:重构Pixelle-Video的模块化潜能
  • SPICE仿真实战:从时序分析基础到建立保持时间验证
  • 一小时快速上手BLDC电机FOC控制:从零到稳定运行的实战指南
  • 【年内检索、连续4届EI检索】第五届电力工程与电气技术学术会议(ICPEET 2026)
  • L298N驱动模块进阶玩法:用Arduino实现直流电机的软启动、缓停与速度曲线控制
  • 2026 中国四辊卷板机权威实力排行榜 - 安徽工业
  • Kafka 旧版本迁移到新集群如何保证数据一致性和完整性?
  • 2026年论文AI率过高怎么破?揭秘高效降AI率的必看神器 - 降AI实验室
  • Linux 进阶运维与 AI 环境实战:进程管理、网络排错与 GPU 监控
  • 别再死记硬背了!用打王者荣耀掉帧的例子,5分钟搞懂视频编码里的I/P/B帧
  • ROS2多机通信避坑指南:为什么你的虚拟机和宿主机能Ping通,但节点就是找不到?
  • 从‘盲人摸象’到‘全局视野’:手把手教你用MATLAB/Simulink仿真PSO-MPPT对抗光伏遮荫(避坑指南)
  • ElementPlus el-tabs组件样式深度定制:从基础美化到高级交互视觉方案
  • 基于Orange Pi 5 Plus与DEEPX栈的边缘AI部署实战指南
  • OpenHuman 深度解析:23k Star 的开源桌面 AI 超级助手完全指南
  • Bifrost三星固件下载器:免费跨平台获取官方系统的一站式解决方案
  • 用Python+OpenCV+SORT搞定高空抛物监测:从摄像头选型到代码调试的保姆级避坑指南
  • 山海再赴,探索向新|2026 第二届搜狐极限探索者大会盛大启航!
  • 福州高三升学集训选机构指南:不同预算不同需求怎么选 - 资讯速览
  • STM32结构体对齐:原理、设置与内存优化实战
  • IaC治理失控?DeepSeek内部用的5层防护网架构,已支撑日均3800+环境自动交付,现在开源核心逻辑
  • 安全元件在固件验证中的三大核心应用:安全启动、运行时保护与OTA升级