Vue 3 响应式原理:Proxy 与 Effect 实现机制

Vue 3 通过 Proxy 代理Effect 依赖收集实现"数据变视图更",核心流程如下:


1. 响应式对象创建(Proxy 代理)

使用 Proxy 拦截对象操作:

function reactive(target) {
  return new Proxy(target, {
    get(obj, key) {
      track(obj, key)  // 依赖收集
      return Reflect.get(obj, key)
    },
    set(obj, key, value) {
      Reflect.set(obj, key, value)
      trigger(obj, key)  // 触发更新
      return true
    }
  })
}

  • Proxy 优势
    原生支持数组/嵌套对象,无需递归初始化(Vue 2 的缺陷)

2. 依赖收集(Effect 系统)

实现依赖跟踪的伪代码:

let activeEffect = null  // 当前激活的副作用

function effect(fn) {
  activeEffect = fn
  fn()  // 执行时触发 getter
  activeEffect = null
}

// 存储依赖关系的数据结构
const targetMap = new WeakMap()  // WeakMap<target, Map<key, Set<effect>>>

function track(target, key) {
  if (!activeEffect) return
  
  let depsMap = targetMap.get(target)
  if (!depsMap) {
    targetMap.set(target, (depsMap = new Map()))
  }
  
  let deps = depsMap.get(key)
  if (!deps) {
    depsMap.set(key, (deps = new Set()))
  }
  
  deps.add(activeEffect)  // 关联当前副作用
}


3. 触发更新(Trigger 机制)
function trigger(target, key) {
  const depsMap = targetMap.get(target)
  if (!depsMap) return
  
  const effects = depsMap.get(key)
  effects && effects.forEach(fn => fn())  // 重新执行所有关联副作用
}


工作流程示例

const state = reactive({ count: 0 })

// 声明响应式副作用
effect(() => {
  console.log(`Count updated: ${state.count}`)
})

state.count++  // 输出 "Count updated: 1"

  1. effect() 执行时触发 state.countgetter
  2. track() 将副作用函数存入 targetMap
  3. state.count++ 触发 setter
  4. trigger() 找到关联的副作用函数并执行

数学关系表示

设:

  • $T$ 为响应式对象
  • $K$ 为对象键值
  • $E$ 为副作用函数集合

依赖关系满足:
$$E = \bigcup_{k \in K} \text{track}(T, k)$$

更新触发条件:
$$\frac{\partial T}{\partial t} \neq 0 \implies \forall e \in E, \text{trigger}(e)$$


与视图更新的关联

在 Vue 组件中:

setup() {
  const state = reactive({ data: [] })
  effect(() => {
    // 虚拟DOM生成(依赖state.data)
    render(virtualDom)
  })
}

数据变更 → 触发 Effect → 重新渲染虚拟 DOM → DOM 差异更新,实现高效视图同步。

Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐