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 主动监听响应式数据变化,执行回调
相关推荐
程序员大阳4 分钟前
副队长JavaScript教程(20)–三元运算符、逗号运算符
javascript·三元运算符·逗号运算符
计算机魔术师8 分钟前
AI渗透框架3小时破云,中国黑客组织正在升级打法
前端
蒲公英内测分发10 分钟前
智能手环出海测试,海外合作方分散在不同国家,Android 测试包怎么持续分发和更新?
android·前端·人工智能·测试工具·智能手表
朱涛的自习室17 分钟前
高价软件已死,我让 AI 开启了「平替计划」(Day 7 / 7)
android·前端·github
沙蒿同学33 分钟前
Wails v3 实战:一个桌面提醒客户端,从 v2 升到 v3 的全过程
前端·后端·github
inquisiter1 小时前
KernelGpt的部分尝试
java·前端·apache
the局外人1 小时前
用 TRAE 把 Markdown文档 搬到微信公众号
前端
Autumn_ing1 小时前
AI原型设计工具怎么选?可编辑原型与可运行前端适合什么场景
前端·小程序·产品经理·代码·codex·墨刀ai客户端·ai原型
夕阳_醉了2 小时前
前端通用组件开发全指南|从 0 到 1 打造稳定可复用的业务组件
前端
Amos_Web2 小时前
Rspack 源码解析(三十):SourceMapDevToolPlugin 如何生成并关联 source map
前端