1. ref的底层实现
ref
的核心作用是将一个值(尤其是基本类型值)包装成一个响应式对象,并通过.value
属性访问和修改。它的实现依赖于RefImpl
类,并通过track
和trigger
机制实现依赖收集和更新触发。
源码分析
kotlin
class RefImpl<T> {
private _value: T
public readonly __v_isRef = true
constructor(private _rawValue: T, public readonly _shallow = false) {
// 将原始值转换为响应式值
this._value = _shallow ? _rawValue : convert(_rawValue)
}
get value() {
// 依赖收集
track(toRaw(this), TrackOpTypes.GET, 'value')
return this._value
}
set value(newVal) {
// 检查值是否发生变化
if (hasChanged(toRaw(newVal), this._rawValue)) {
this._rawValue = newVal
// 更新值并转换为响应式
this._value = this._shallow ? newVal : convert(newVal)
// 触发更新
trigger(toRaw(this), TriggerOpTypes.SET, 'value', newVal)
}
}
}
function ref(value) {
return createRef(value)
}
function createRef(rawValue, shallow = false) {
if (isRef(rawValue)) {
return rawValue
}
return new RefImpl(rawValue, shallow)
}
关键点分析
RefImpl
类 :ref
的核心实现类,通过get
和set
访问器拦截对.value
的访问和修改。get
:在访问.value
时,调用track
进行依赖收集。set
:在修改.value
时,调用trigger
触发更新。
convert
函数 :将原始值转换为响应式值。如果原始值是对象,则调用reactive
将其转换为响应式对象。track
和trigger
:Vue 3的响应式系统的核心机制,分别用于依赖收集和更新触发。
设计思想
ref
的设计是为了解决基本类型值的响应式问题。由于JavaScript的Proxy
无法直接代理基本类型值(如number
、string
等),ref
通过将值包装在对象中,实现了对基本类型值的响应式支持。
2. reactive的底层实现
reactive
的核心作用是创建一个响应式对象,它通过Proxy
代理对象的属性访问和修改,从而实现对整个对象的响应式处理。
源码分析
javascript
function reactive(target) {
if (target && target.__v_isReadonly) {
return target
}
return createReactiveObject(
target,
false,
mutableHandlers,
mutableCollectionHandlers
)
}
function createReactiveObject(
target,
isReadonly,
baseHandlers,
collectionHandlers
) {
if (!isObject(target)) {
return target
}
// 创建Proxy代理
const proxy = new Proxy(target, baseHandlers)
return proxy
}
关键点分析
Proxy
代理 :reactive
通过Proxy
代理目标对象,拦截对对象属性的访问和修改。get
:在访问属性时,调用track
进行依赖收集。set
:在修改属性时,调用trigger
触发更新。
mutableHandlers
:Proxy
的处理器对象,定义了get
、set
、deleteProperty
等拦截器。createReactiveObject
函数 :负责创建Proxy
代理对象,并处理边界情况(如只读对象、非对象值等)。
设计思想
reactive
的设计是为了处理复杂对象的响应式问题。它通过Proxy
代理对象的属性,实现了对整个对象的深度响应式支持。与ref
相比,reactive
更适合处理复杂数据结构(如对象、数组等)。
3. ref和reactive的区别
4. 总结
ref
:通过RefImpl
类将值包装为响应式对象,适合处理基本类型值或单一对象的响应式需求。reactive
:通过Proxy
代理整个对象,适合处理复杂对象的响应式需求。
在实际开发中,ref
和reactive
可以结合使用。例如,可以将一个对象的某个属性用ref
包装,而将整个对象用reactive
处理。理解它们的底层实现和设计思想,有助于更好地选择和使用这两种响应式工具。
5. 后续
下一篇咱们分析一下track
和trigger
的实现逻辑,刨根问底才是真!