🧬 Vue 3 响应式核心源码详解(基于 @vue/reactivity)

⚙️ 整理不易,记得点赞、收藏、关注,揭开 Vue 响应式的神秘面纱!


🧭 一、源码结构总览(relevant files)

Vue 的响应式系统主要在 @vue/reactivity 包中,核心源码文件包括:

文件名作用说明
reactive.ts创建响应式对象的入口
ref.ts实现 ref 响应式数据
effect.ts实现副作用追踪(依赖收集与触发)
computed.ts实现 computed 的缓存逻辑
watch.ts实现 watch 响应逻辑
baseHandlers.ts代理对象的拦截逻辑(get/set)
reactiveEffect.ts核心依赖收集机制(调度系统)

我们将通过 执行流程 + 源码解构 + 关键机制 三个部分讲透它👇


🔍 二、响应式系统的运行流程(大局观)

  1. 使用 reactive(obj)ref(value) 创建响应式数据;
  2. 使用响应式数据的地方(如组件、computed)注册为“副作用函数” ReactiveEffect
  3. 数据被访问时会收集依赖(track);
  4. 数据被修改时会触发依赖(trigger);
  5. 依赖更新后触发副作用函数(如组件更新、watch 回调、computed 重算)。

🧠 本质上,是一个“数据和函数之间的订阅-发布机制”。


🧪 三、关键源码拆解


1️⃣ reactive 的本质:Proxy 包裹对象

export function reactive(target: object): object {return createReactiveObject(target, false, mutableHandlers)
}

实际调用的是 createReactiveObject,它的核心逻辑:

function createReactiveObject(target, isReadonly, baseHandlers) {const proxy = new Proxy(target, baseHandlers)return proxy
}

配合 mutableHandlers.ts 中的 get 拦截器:

get(target, key, receiver) {const res = Reflect.get(target, key, receiver)track(target, 'get', key)  // 依赖收集return isObject(res) ? reactive(res) : res
}

📌 重点:每次读取属性,会调用 track() 做依赖收集!


2️⃣ ref 的本质:包裹值 + 自定义 getter/setter

export function ref(value) {return createRef(value)
}
function createRef(rawValue) {const r = {get value() {track(r, 'get', 'value') // 收集依赖return rawValue},set value(newVal) {rawValue = newValtrigger(r, 'set', 'value') // 触发更新}}return r
}

✅ ref 是通过 getter/setter 控制单值的响应式行为。


3️⃣ track:收集依赖

const targetMap = new WeakMap()export function track(target, type, key) {if (!activeEffect) returnlet depsMap = targetMap.get(target)if (!depsMap) {depsMap = new Map()targetMap.set(target, depsMap)}let dep = depsMap.get(key)if (!dep) {dep = new Set()depsMap.set(key, dep)}dep.add(activeEffect) // 绑定副作用函数
}

每个对象的 key -> Set(effect),形成完整依赖图。


4️⃣ trigger:触发依赖

export function trigger(target, type, key) {const depsMap = targetMap.get(target)if (!depsMap) returnconst effects = depsMap.get(key)if (effects) {effects.forEach(effect => {effect()})}
}

数据变了,就找到 key 对应的 effect 执行回调!


5️⃣ ReactiveEffect 类:副作用的封装载体

export class ReactiveEffect {constructor(fn, scheduler) {this.fn = fnthis.scheduler = scheduler}run() {activeEffect = thisreturn this.fn()}
}

用于封装副作用函数,例如 watchcomputed、组件更新逻辑等。


6️⃣ computed 的实现:带缓存的 ReactiveEffect

export function computed(getter) {let valuelet dirty = trueconst effect = new ReactiveEffect(getter, () => {dirty = truetrigger(obj, 'set', 'value')})const obj = {get value() {if (dirty) {value = effect.run()dirty = false}track(obj, 'get', 'value')return value}}return obj
}
  • 懒执行:只有在 .value 被访问时才执行
  • 缓存机制:依赖没变不会重新执行 getter

7️⃣ watch 的实现:注册一个副作用函数,包裹 source

export function watch(source, cb, options?) {let getter = () => source.value // 简化const job = () => {const newVal = effect.run()cb(newVal, oldVal)oldVal = newVal}const effect = new ReactiveEffect(getter, job)if (options.immediate) job()else oldVal = effect.run()
}
  • 自动依赖收集
  • 值变化后执行 job 调用回调

📦 四、响应式系统核心图示总结

          +-------------------------+|     reactive/ref       |+-------------------------+|↓ Proxy or Getter|+--------------+|  track()     | ← 收集依赖+--------------+|+--------------+| trigger()    | → 执行副作用+--------------+|+---------------------------+| ReactiveEffect(fn)       |+---------------------------+↑          ↓run()       scheduler(watch/computed)

🧠 五、总结一下

机制功能说明
reactiveProxy 代理对象,拦截 get/set 实现响应式
ref定义 .value 属性,包裹单值响应式
track收集依赖到 effect
trigger执行依赖的 effect
ReactiveEffect封装副作用函数
computed带缓存的懒执行响应式副作用
watch主动监听响应式数据变化,执行回调

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

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

相关文章

编写shell脚本扫描工具,扫描服务器开放了哪些端口(再尝试用python编写一个)

先将需要扫描的服务器的端口显示出来,然后再显示哪些ip地址对应的服务器的哪些端口已开放或未开放 下面这个shell脚本可以同时扫描多个ip对应的多个服务器的多个端口是否开放: 以下是运行结果: nc 和 nmap 扫描别人的机器开放了哪些端口 ne…

java JNDI高版本绕过 工具介绍 自动化bypass

JNDI高版本rce失效问题 原因: 主要还是协议控制高版本的一般都会关闭如rmi,ldap等协议远程加载的类 RMI限制: com.sun.jndi.rmi.object.trustURLCodebase、com.sun.jndi.cosnaming.object.trustURLCodebase的默认值变为false,即…

JavaWeb笔记02

三、数据库设计 1_简介 1.数据库设计设计什么? 有哪些表 表里有哪些字段 表和表之间是什么关系 2.表关系有哪几种? 一对一 一对多(多对一) 多对多 2_多表关系实现 表关系之一对多 一对多 (多对一): 如:部门表和员…

Junit_注解_枚举

文章目录 一:Junit单元测试测试分类:Junit的使用Before_After 二:注解什么是注解文档相关的注解IDEA中的javadoc使用:JDK内置的3个注解自定义注解 元注解RetentionTargetRepeatableDocumented(用的很少)Inh…

将N8N配置为服务【ubuntu】

docker模式不在此讨论。这里讨论的是node安装为n8n后,如何安装为服务: 安装NODE(略) 安装N8N 一个命令解决: npm install n8n -g 安装服务 vi /etc/systemd/system/n8n.service内容如下 [Unit] Descriptionn8…

Java后端调用外部接口标准流程详解

在Java后端开发中,调用外部HTTP接口(如第三方平台API、云服务、微服务等)是非常常见的需求。实现这个功能通常遵循一套标准的流程: 1. 准备DTO类(数据传输对象) 作用: DTO(Data Tra…

星火燎原 数智新生 —— 《GB/T 45341—2025》 × AI大模型 × 全域PaaS创新,领码SPARK打造行业数字化转型新范式

【摘要】 数字中国新征程,标准引航数智化。面对企业数字蝶变的关键关口,《GB/T 45341—2025 数字化转型管理 参考架构》引领行业规范发展。爱分析最新数据显示,中国iPaaS市场规模持续高增长,印证PaaS已成为企业数字化基石。 AI大…

25-7-1 论文学习(1)- Fractal Generative Models 何恺明大佬的论文

分形生成模型 Tianhong Li1 Qinyi Sun1 Lijie Fan2 Kaiming He1 摘要 模块化是计算机科学的基石,它将复杂函数抽象为原子构建块。在本文中,我们通过将生成模型抽象为原子生成模块,引入了新的模块化层次。类似于数学中的分形,我…

如何读取运行jar中引用jar中的文件

1.问题发现 项目中有个common包资源文件,然后springboot项目引用了common,那么我们要怎么读取这个资源了。这里需要考虑三个场景,idea运行时、common jar独立运行时、springboot引用common后运行时。 2.问题解决 2.1.idea运行时 Protection…

【学习方法】框架质疑学习法:破解专业学习的“知识厚度”困境

今天博主给大家分享一个,我自己发明了一个比较高效的学习方法,名叫“框架质疑学习法” 本文提出的框架质疑学习法(Framework Questioning Learning Method)为本文作者,也就是我,董翔首次提出。 在软件专业的学习中&a…

spring-ai 1.0.0 学习(十七)——MCP Client

之前学过了工具调用(spring-ai 1.0.0 学习(十二)——工具调用_springai 1.0 如何判断调用哪一个tool工具-CSDN博客),今天来看一下MCP MCP是什么 MCP全称是模型上下文协议,有点绕,通俗点理解&a…

Git 运行.sh文件

1.在项目文件中右击 Open Git Bash here 显示(base)环境 2.激活conda环境 3.复制.sh文件的相对路径 4.将路径复制到git终端 先输入sh和空格,然后右击后选paste,不要直接ctrl v 5.开始运行

MySQL InnoDB 引擎中的聚簇索引和非聚簇索引有什么区别?

MySQL InnoDB 引擎中的聚簇索引和非聚簇索引有什么区别? 主要解答详细解答1. **聚簇索引(Clustered Index)**2. **非聚簇索引(Non-Clustered Index / Secondary Index)**3. **对比总结**4. **流程图(查询过…

[2025CVPR]DE-GANs:一种高效的生成对抗网络

目录 引言:数据高效GAN的困境 核心原理:动态质量筛选机制 1. 判别器拒绝采样(DRS)的再思考 2. 质量感知动态拒绝公式 (1)质量感知阶段 (2)动态拒绝阶段 模型架构:轻量化设计 技术突破:三大创新点 1. 首创训练阶段DRS 2. 动态拒绝机制 3. 质量重加权策略 …

[面试] 手写题-数组转树

示例数据: const arr [{ id: 1, parentId: null, name: Root },{ id: 2, parentId: 1, name: Child 1 },{ id: 3, parentId: 1, name: Child 2 },{ id: 4, parentId: 2, name: Grandchild 1 }, ]目标生成: const tree [{id: 1,name: Root,children: …

CertiK《Hack3d:2025年第二季度及上半年Web3.0安全报告》(附报告全文链接)

CertiK《Hack3d:2025年第二季度及上半年Web3.0安全报告》现已发布,报告显示:仅2025年上半年,因安全事件导致的损失接近25亿美元;截至目前,总损失已超过去年全年水平。整体来看,Web3.0安全形势依…

反向传播 梯度消失

反向传播 backpropagation 反向传播(Backpropagation) 是神经网络训练中的一种核心算法,用于通过计算误差并将其传播回网络,从而更新神经网络的参数。通过反向传播,网络能够在每次迭代中逐步调整其参数(例…

京东外卖服务商加入方案对比!选择本地生活服务商系统的优势,到底在哪?

自入局之日起,京东外卖似乎就一直热衷于给人惊喜: 先是在上线时规定了“2025年5月1日前入驻的商家,全年免佣金”和“仅限品质堂食商家入驻”; 再是宣布了要为外卖骑手缴纳五险一金,并承担其中的所有成本;…

【RTSP从零实践】4、使用RTP协议封装并传输AAC

😁博客主页😁:🚀https://blog.csdn.net/wkd_007🚀 🤑博客内容🤑:🍭嵌入式开发、Linux、C语言、C、数据结构、音视频🍭 🤣本文内容🤣&a…

Bootstrap 安装使用教程

一、Bootstrap 简介 Bootstrap 是一个开源的前端框架,由 Twitter 开发,旨在快速开发响应式、移动优先的 Web 页面。它包含 HTML、CSS 和 JavaScript 组件,如按钮、导航栏、表单等。 二、Bootstrap 安装方式 2.1 使用 CDN(推荐入…