vue3-响应式高级篇(三)

106 阅读1分钟

这篇主要是对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);
}

github1s.com/vuejs/core/…

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来判断,是就返回原值