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

发布于:2025-07-01 ⋅ 阅读:(24) ⋅ 点赞:(0)

🧬 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 = newVal
      trigger(r, 'set', 'value') // 触发更新
    }
  }
  return r
}

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


3️⃣ track:收集依赖

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:触发依赖

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 类:副作用的封装载体

export class ReactiveEffect {
  constructor(fn, scheduler) {
    this.fn = fn
    this.scheduler = scheduler
  }

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

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


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

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

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)

🧠 五、总结一下

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

网站公告

今日签到

点亮在社区的每一天
去签到