Vue 3 响应式原理:Proxy 代理与 Effect 依赖收集如何实现 “数据变视图更”
·
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"
effect()执行时触发state.count的 gettertrack()将副作用函数存入targetMapstate.count++触发 settertrigger()找到关联的副作用函数并执行
数学关系表示
设:
- $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 差异更新,实现高效视图同步。
更多推荐
所有评论(0)