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

🧬 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 包裹对象

ts 复制代码
export function reactive(target: object): object {
  return createReactiveObject(target, false, mutableHandlers)
}

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

ts 复制代码
function createReactiveObject(target, isReadonly, baseHandlers) {
  const proxy = new Proxy(target, baseHandlers)
  return proxy
}

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

ts 复制代码
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

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

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


3️⃣ track:收集依赖

ts 复制代码
const targetMap = new WeakMap()

export function track(target, type, key) {
  if (!activeEffect) return
  let 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:触发依赖

ts 复制代码
export function trigger(target, type, key) {
  const depsMap = targetMap.get(target)
  if (!depsMap) return
  const effects = depsMap.get(key)
  if (effects) {
    effects.forEach(effect => {
      effect()
    })
  }
}

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


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

ts 复制代码
export class ReactiveEffect {
  constructor(fn, scheduler) {
    this.fn = fn
    this.scheduler = scheduler
  }

  run() {
    activeEffect = this
    return this.fn()
  }
}

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


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

ts 复制代码
export function computed(getter) {
  let value
  let dirty = true

  const effect = new ReactiveEffect(getter, () => {
    dirty = true
    trigger(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

ts 复制代码
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 调用回调

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

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

🧠 五、总结一下

机制 功能说明
reactive 用 Proxy 代理对象,拦截 get/set 实现响应式
ref 定义 .value 属性,包裹单值响应式
track 收集依赖到 effect
trigger 执行依赖的 effect
ReactiveEffect 封装副作用函数
computed 带缓存的懒执行响应式副作用
watch 主动监听响应式数据变化,执行回调
相关推荐
treasure140几秒前
【复古】浅尝Django前后端不分离
前端·css·python·django·bootstrap·html·web
jay神1 小时前
基于 YOLOv8 的手势识别系统(Web 版)
前端·人工智能·python·深度学习·yolo·计算机视觉·计算机毕业设计
屏什么录1 小时前
长时间录屏中途崩溃:MP4 打不开的 6 种救回方案与参数设置
前端·音视频开发
ruanno_top1 小时前
表单重置后,验证码还显示已通过:Vue 受控组件的 3 种假同步
vue.js
code_Bo2 小时前
不只命令行:我把跨 Agent 会话同步做成了桌面应用
前端·javascript·后端
kyriewen2 小时前
AI 能把页面写出来,为什么改个需求就开始崩?
前端·javascript·人工智能
OpsEye2 小时前
同一套用例跑两个大模型接口,差异到底出在哪
javascript·ai编程
X1A0RAN3 小时前
PPT 图片批量处理教程:导出全部幻灯片 · 提取全部素材
开发语言·javascript·powerpoint
涛涛ing3 小时前
2026年最值得关注的前端变化,藏在“默认值”里
前端
量化分析码农4 小时前
股票历史数据的复权参数对照:多级别返回的字段与数值差异
java·javascript·后端