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()
  }
}

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


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 主动监听响应式数据变化,执行回调
相关推荐
珍宝商店15 小时前
前端老旧项目全面性能优化指南与面试攻略
前端·面试·性能优化
bitbitDown15 小时前
四年前端分享给你的高效开发工具库
前端·javascript·vue.js
YAY_tyy15 小时前
【JavaScript 性能优化实战】第六篇:性能监控与自动化优化
javascript·性能优化·自动化
gnip16 小时前
实现AI对话光标跟随效果
前端·javascript
脑花儿17 小时前
ABAP SMW0下载Excel模板并填充&&剪切板方式粘贴
java·前端·数据库
闭着眼睛学算法18 小时前
【华为OD机考正在更新】2025年双机位A卷真题【完全原创题解 | 详细考点分类 | 不断更新题目 | 六种主流语言Py+Java+Cpp+C+Js+Go】
java·c语言·javascript·c++·python·算法·华为od
烛阴18 小时前
【TS 设计模式完全指南】构建你的专属“通知中心”:深入观察者模式
javascript·设计模式·typescript
lumi.18 小时前
Vue.js 从入门到实践1:环境搭建、数据绑定与条件渲染
前端·javascript·vue.js
二十雨辰18 小时前
vue核心原理实现
前端·javascript·vue.js
影子信息18 小时前
[Vue warn]: Error in mounted hook: “ReferenceError: Jessibuca is not defined“
前端·javascript·vue.js