reactive与ref的实现机制
在Vue3的响应式系统中,reactive
与ref
是核心API,它们分别针对对象和基本类型数据实现响应式。两者底层均依赖Proxy和依赖收集机制,但在使用场景和内部实现上存在显著差异。
reactive的实现机制
reactive
通过Proxy代理目标对象,拦截属性的读取(get)和设置(set)操作。当访问属性时,触发track
函数收集依赖;当修改属性时,触发trigger
函数通知更新。以下是简化实现:
function reactive(target) {
return new Proxy(target, {
get(target, key, receiver) {
track(target, key) // 依赖收集
return Reflect.get(target, key, receiver)
},
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 reactive(target) {
if (isObject(target)) {
Object.entries(target).forEach(([key, val]) => {
if (isObject(val)) target[key] = reactive(val)
})
}
return /* Proxy逻辑 */
}
对于数组的特殊处理体现在拦截push
等方法:
const arrayInstrumentations = {
push(...args) {
const res = Array.prototype.push.apply(this, args)
trigger(this, 'length') // 手动触发length变更
return res
}
}
ref的实现机制
ref
通过对象包装基本类型值,利用value
属性访问实际值。其核心实现如下:
function ref(value) {
return {
get value() {
track(this, 'value') // 收集依赖
return value
},
set value(newVal) {
if (newVal !== value) {
value = newVal
trigger(this, 'value') // 触发更新
}
}
}
}
对象类型处理存在优化:
function ref(value) {
return isObject(value)
? reactive(value) // 直接转为reactive
: createRef(value)
}
模板中自动解包特性通过编译阶段实现:
<script setup>
const count = ref(0)
</script>
<template>
<!-- 编译为count.value -->
<button @click="count++">{{ count }}</button>
</template>
两者差异对比
性能方面,ref
在基本类型场景更高效:
// 创建10000个响应式变量
const refs = Array(10000).fill(0).map(() => ref(0)) // 更快
const reactives = Array(10000).fill(0).map(() => reactive({ value: 0 }))
类型系统支持差异明显:
const numRef = ref<number>(0) // 明确类型
const objReactive = reactive<{ foo: string }>({ foo: 'bar' }) // 自动推断
解构行为对比:
const state = reactive({ x: 1, y: 2 })
const { x } = state // 失去响应性
const xRef = toRef(state, 'x') // 保持响应性
底层依赖追踪系统
track
函数建立依赖关系:
const targetMap = new WeakMap()
function track(target, key) {
if (!activeEffect) return
let depsMap = targetMap.get(target)
if (!depsMap) targetMap.set(target, (depsMap = new Map()))
let dep = depsMap.get(key)
if (!dep) depsMap.set(key, (dep = new Set()))
dep.add(activeEffect)
}
trigger
函数触发更新:
function trigger(target, key) {
const depsMap = targetMap.get(target)
if (!depsMap) return
const effects = depsMap.get(key)
effects && effects.forEach(effect => effect())
}
特殊场景处理
readonly
实现共享部分逻辑:
function readonly(target) {
return new Proxy(target, {
get: createGetter(true),
set(target, key) {
console.warn(`Set operation on key "${key}" failed: target is readonly.`)
return true
}
})
}
shallowReactive
的浅层响应:
function shallowReactive(target) {
return new Proxy(target, {
get(target, key) {
track(target, key)
const res = Reflect.get(target, key)
return isObject(res) ? res : reactive(res) // 不递归处理
}
})
}
响应式API的演进
Vue3.3引入的reactivity transform
:
// 编译前
let count = $ref(0)
function increment() {
count++
}
// 编译后
let count = ref(0)
function increment() {
count.value++
}
与Composition API的配合:
function useCounter() {
const count = ref(0)
const double = computed(() => count.value * 2)
return { count, double }
}
本站部分内容来自互联网,一切版权均归源网站或源作者所有。
如果侵犯了你的权益请来信告知我们删除。邮箱:cc@cccx.cn
上一篇:源码调试环境的搭建
下一篇:依赖收集与追踪的详细流程