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 主动监听响应式数据变化,执行回调
相关推荐
计算机魔术师22 分钟前
AMD砸82亿买下李飞飞,这次不卖芯片卖什么?
前端
hzxpaipai1 小时前
杭州企业官网怎么建设?从策划到上线的5步建站方法
运维·服务器·前端·网络
怕浪猫1 小时前
2026年金九银十,我面了22个前端
前端·javascript·面试
IT_陈寒1 小时前
Vue 这个响应式陷阱,我的头发都掉没了
前端·人工智能·后端
FYKJ_20101 小时前
django电影推荐系统55066-计算机课程设计、毕业设计
vue.js·spring boot·python·mysql·typescript·spark·django
前端的日常1 小时前
一个人+AI做情侣食谱小程序,30天纯赚
前端·javascript·后端
qq_316837752 小时前
阿里云百炼 fun-asr-realtime uniapp vue3 调用
javascript·vue.js·uni-app
庄园特聘拆椅狂魔2 小时前
Java 后端转全栈的第一课:从前端项目搭建到技术选
java·开发语言·前端
triumph_passion2 小时前
前端路由策略:Memory、Hash 与 History
前端
李剑一2 小时前
AntDesign老版本没有月份和年份区间选择组件?我封装了一个完美版,附源码!
前端·vue.js