持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第15天,点击查看活动详情
前言
Ref 接受一个内部值并返回一个响应式且可变的 ref 对象。ref 对象仅有一个 .value 属性,指向该内部值。它和同样是能把数据变成响应式的 reactive 有什么区别呢?
- reactive 一般推荐用来定义复杂的数据类型,ref一般推荐用于定义基本类型。
- ref操作数据需要通过
.value来访问,在template模板中则不需要。而reactive都不需要通过.value访问
使用
ref 方法接受一个值,变为响应式,然后访问时需要通过这个响应式对象的 value 属性啦哎访问
import { ref } from 'vue'
const count = ref(0)
console.log(count.value) // 0
count.value++
console.log(count.value) // 1
通过ref方法的类型声明为:
interface Ref<T> {
value: T
}
function ref<T>(value: T): Ref<T>
可以看到,里面只有一个 value 属性。
源码
ref 的方法在 /packages/reactivity/src/ref.ts 文件中。
// packages/reactivity/src/ref.ts
export function ref(value?: unknown) {
return createRef(value, false)
}
里面只做了一件事,返回 createRef 的值,createRef 接受两个参数,value和shallow,shallow 表明是否为 shallowRef 的浅层响应式 api。
function createRef(rawValue: unknown, shallow: boolean) {
if (isRef(rawValue)) {
return rawValue
}
return new RefImpl(rawValue, shallow)
}
如果value 值已经时 ref 对象,则直接返回,否则通过实例化类 RefImpl 来创建ref对象。
RefImpl 类
class RefImpl<T> {
private _value: T
private _rawValue: T
public dep?: Dep = undefined
public readonly __v_isRef = true
constructor(value: T, public readonly __v_isShallow: boolean) {
this._rawValue = __v_isShallow ? value : toRaw(value)
this._value = __v_isShallow ? value : toReactive(value)
}
get value() {
trackRefValue(this)
return this._value
}
set value(newVal) {
newVal = this.__v_isShallow ? newVal : toRaw(newVal)
if (hasChanged(newVal, this._rawValue)) {
this._rawValue = newVal
this._value = this.__v_isShallow ? newVal : toReactive(newVal)
triggerRefValue(this, newVal)
}
}
}
RefImpl 中有私有变量 _value 和 _rawValue,它们分别代表,ref的最新的值和旧值。
只读变量 __v_isRef 用来标识这个对象为 ref 类型的对象。
公共变量 dep 用来保存依赖。
里面有两个方法 get value 和 set value,当我们通过 .value 访问值的时候,就会触发get value,设置value的时候就会触发set value。
在 getter 中通过 trackRefValue 进行收集依赖。track 具体实现我们在上一篇已经详细讲过,这里的 trackRefValue 原理是一样的。
在 setter 中首先判断值是否改变了,如果改变则进行重新赋值,和触发依赖进行派发更新。
小结
ref 的总体代码还是比较简单的,也是通过 getter和setter进行依赖收集和更新。