Vue3 响应式系统实现
手写 Vue3 简易响应式,包含 Proxy、reactive 和 effect
问题
从零实现 Vue3 的响应式系统,包括 reactive 和 effect 函数。
解答
依赖收集系统
// 当前正在执行的 effect
let activeEffect = null
// 存储依赖关系:WeakMap<target, Map<key, Set<effect>>>
const targetMap = new WeakMap()
// 收集依赖
function track(target, key) {
if (!activeEffect) return
let depsMap = targetMap.get(target)
if (!depsMap) {
depsMap = new Map()
targetMap.set(target, depsMap)
}
let deps = depsMap.get(key)
if (!deps) {
deps = new Set()
depsMap.set(key, deps)
}
deps.add(activeEffect)
}
// 触发更新
function trigger(target, key) {
const depsMap = targetMap.get(target)
if (!depsMap) return
const deps = depsMap.get(key)
if (deps) {
deps.forEach(effect => effect())
}
}
实现 reactive
function reactive(obj) {
return new Proxy(obj, {
get(target, key, receiver) {
const result = Reflect.get(target, key, receiver)
// 收集依赖
track(target, key)
// 如果是对象,递归代理
if (typeof result === 'object' && result !== null) {
return reactive(result)
}
return result
},
set(target, key, value, receiver) {
const oldValue = target[key]
const result = Reflect.set(target, key, value, receiver)
// 值变化时触发更新
if (oldValue !== value) {
trigger(target, key)
}
return result
}
})
}
实现 effect
function effect(fn) {
const effectFn = () => {
activeEffect = effectFn
fn()
activeEffect = null
}
// 立即执行一次,收集依赖
effectFn()
return effectFn
}
测试代码
const state = reactive({
count: 0,
user: {
name: 'Tom'
}
})
// 注册副作用
effect(() => {
console.log('count:', state.count)
})
effect(() => {
console.log('name:', state.user.name)
})
// 修改数据,自动触发更新
state.count++ // 输出: count: 1
state.user.name = 'Jerry' // 输出: name: Jerry
完整代码
let activeEffect = null
const targetMap = new WeakMap()
function track(target, key) {
if (!activeEffect) return
let depsMap = targetMap.get(target)
if (!depsMap) {
depsMap = new Map()
targetMap.set(target, depsMap)
}
let deps = depsMap.get(key)
if (!deps) {
deps = new Set()
depsMap.set(key, deps)
}
deps.add(activeEffect)
}
function trigger(target, key) {
const depsMap = targetMap.get(target)
if (!depsMap) return
const deps = depsMap.get(key)
if (deps) {
deps.forEach(effect => effect())
}
}
function reactive(obj) {
return new Proxy(obj, {
get(target, key, receiver) {
const result = Reflect.get(target, key, receiver)
track(target, key)
if (typeof result === 'object' && result !== null) {
return reactive(result)
}
return result
},
set(target, key, value, receiver) {
const oldValue = target[key]
const result = Reflect.set(target, key, value, receiver)
if (oldValue !== value) {
trigger(target, key)
}
return result
}
})
}
function effect(fn) {
const effectFn = () => {
activeEffect = effectFn
fn()
activeEffect = null
}
effectFn()
return effectFn
}
关键点
- WeakMap 存储依赖:
targetMap -> depsMap -> deps三层结构,WeakMap 不阻止垃圾回收 - Proxy 拦截操作:get 时收集依赖,set 时触发更新
- Reflect 配合 Proxy:保证 this 指向正确,处理继承场景
- activeEffect 标记:用全局变量记录当前执行的 effect,实现自动依赖收集
- 嵌套对象处理:get 时递归调用 reactive,实现深层响应式
目录