深入解析Vue3中ref与reactive的区别及源码实现
前言
Vue3带来了全新的响应式系统,其中ref
和reactive
是最常用的两个API。本文将从基础使用、核心区别到源码实现,由浅入深地分析这两个API。
一、基础使用
1. ref
import { ref } from vue
const count = ref(0)
console.log(count.value) // 0
count.value++
2. reactive
import { reactive } from vue
const state = reactive({ count: 0 })
console.log(state.count) // 0
state.count++
二、核心区别
1. 数据类型
ref
可以包装任意值类型(原始值、对象)reactive
只能处理对象类型
2. 访问方式
ref
需要通过.value
访问reactive
直接访问属性
3. 解构行为
ref
解构后仍保持响应性reactive
解构后会丢失响应性
4. 性能考量
ref
更适合独立的基本类型值reactive
更适合复杂对象
三、源码实现解析
1. ref实现原理
// packages/reactivity/src/ref.ts
class RefImpl<T> {
private _value: T
private _rawValue: T
public dep?: Dep = undefined
public readonly __v_isRef = true
constructor(value: T) {
this._rawValue = value
this._value = convert(value)
}
get value() {
trackRefValue(this)
return this._value
}
set value(newVal) {
newVal = convert(newVal)
if (hasChanged(newVal, this._rawValue)) {
this._rawValue = newVal
this._value = newVal
triggerRefValue(this)
}
}
}
2. reactive实现原理
// packages/reactivity/src/reactive.ts
function reactive(target: object) {
if (isReadonly(target)) {
return target
}
return createReactiveObject(
target,
false,
mutableHandlers,
mutableCollectionHandlers
)
}
function createReactiveObject(
target: Target,
isReadonly: boolean,
baseHandlers: ProxyHandler<any>,
collectionHandlers: ProxyHandler<any>
) {
// 使用Proxy进行代理
const proxy = new Proxy(
target,
targetType === TargetType.COLLECTION ? collectionHandlers : baseHandlers
)
proxyMap.set(target, proxy)
return proxy
}
四、最佳实践
- 基本类型优先使用
ref
- 复杂对象使用
reactive
- 组合使用时注意解构问题
- 大型项目考虑使用
toRefs
保持响应性
五、总结
ref
和reactive
都是Vue3响应式系统的核心,理解它们的区别和实现原理,能帮助我们更好地使用Vue3开发应用。