这篇主要是对api ref的实现,主要是在reactive和effect的基础上实现的。
文档:v3.cn.vuejs.org/api/refs-ap…
接受一个内部值并返回一个响应式且可变的 ref 对象。ref 对象仅有一个 .value
property,指向该内部值。
示例:
const count = ref(0)
console.log(count.value) // 0
effect(()=>{
console.log(count.value)// 当count更新时,这个要重新执行
})
setTImeout(()=>{
count.value++
})
如果将对象分配为 ref 值,则它将被 reactive 函数处理为深层的响应式对象。
源码
同watch
类似。
- ref.ts
import { isTracking, trackEffects, triggerEffects } from "./effect";
import { toReactive } from "./reactive";
class RefImpl{
public dep;
public __v_isRef;
public _value;
constructor(public _rawValue){ // 原来的值
// _rawValue如果用户传进来的值 是一个对象 我需要将对象转化成响应式
this._value = toReactive(_rawValue)
}
// 类的属性访问器 最终会变成deifneProperty
get value(){ // 取值的时候进行依赖收集
if(isTracking()){
trackEffects(this.dep || (this.dep = new Set()));
}
return this._value;
}
set value(newValue){ // 设置的时候触发更新
if(newValue !== this._rawValue){
// 先看一下之前之后是否一样
this._rawValue = newValue; //更新
// 重新进行响应式的绑定
this._value = toReactive(newValue);
// 值更新,需要重新执行依赖相关的effect们。
triggerEffects(this.dep);
}
}
}
function createRef(value){
return new RefImpl(value);
}
export function ref(value){
return createRef(value);
}
export const toReactive = <T extends unknown>(value: T): T =>
isObject(value) ? reactive(value) : value
总结
1.ref
可以传入参数对象或者基础类型,如果是对象则用reactive
包裹,如果不是,则作为ref
类的value
值存储
2.同computed
一样,在get
中收集effect
依赖存储到dep
中;
在set
中赋予新值时,响应式更新(触发effect
依赖数组的重新执行),由于基础类型,要给新值重新绑定响应式。
- 重复ref定义的问题,同reactive一样,访问is_ref 属性判断是否是true来判断,是就返回原值