Vue3响应式原理-Ref

5 篇文章 0 订阅

Vue3响应式原理-Ref

Ref的概念

proxy代理的目标必须是非原始值,所以reactive不支持原始值类型。所以我们需要将原始值类型进行包装。

const flag = ref(false)
effect(()=>{
    document.body.innerHTML = flag.value ? 30:'姜文'
});
setTimeout(()=>{
    flag.value = true
},1000);

Ref & ShallowRef

function createRef(rawValue, shallow) {
    return new RefImpl(rawValue,shallow); // 将值进行装包
}
// 将原始类型包装成对象, 同时也可以包装对象 进行深层代理
export function ref(value) {
    return createRef(value, false);
}
// 创建浅ref 不会进行深层代理
export function shallowRef(value) {
    return createRef(value, true);
}
function toReactive(value) { // 将对象转化为响应式的
    return isObject(value) ? reactive(value) : value
}
class RefImpl {
    public _value;
    public dep;
    public __v_isRef = true;
    constructor(public rawValue, public _shallow) {
        this._value = _shallow ? rawValue : toReactive(rawValue); // 浅ref不需要再次代理
    }
    get value(){
        if(activeEffect){
            trackEffects(this.dep || (this.dep = new Set)); // 收集依赖
        }
        return this._value;
    }
    set value(newVal){
        if(newVal !== this.rawValue){
            this.rawValue = newVal;
            this._value = this._shallow ? newVal : toReactive(newVal);
            triggerEffects(this.dep); // 触发更新
        }
    }
}

toRef & toRefs

响应式丢失问题

const state = reactive({name: 'jw', age: 30 })
let person = {...state}
effect(()=>{
    document.body.innerHTML = person.name +'今年' + person.age +'岁了'
})
setTimeout(()=>{
    person.age = 31;
},1000)

如果将响应式对象展开则会丢失响应式的特性

class ObjectRefImpl {
    public __v_isRef = true
    constructor(public _object, public _key) { }
    get value() {
        return this._object[this._key];
    }
    set value(newVal) {
        this._object[this._key] = newVal;
    }
}
export function toRef(object, key) { // 将响应式对象中的某个属性转化成ref
    return new ObjectRefImpl(object, key);
}
export function toRefs(object) { // 将所有的属性转换成ref
    const ret = Array.isArray(object) ? new Array(object.length) : {};
    for (const key in object) {
        ret[key] = toRef(object, key);
    }
    return ret;
}
let person = {...toRefs(state)}; // 解构的时候将所有的属性都转换成ref即可
effect(()=>{
    document.body.innerHTML = person.name.value +'今年' + person.age.value +'岁了'
})
setTimeout(()=>{
    person.age.value = 31;
},1000)

自动脱ref

let person = proxyRefs({...toRefs(state)})
effect(()=>{
    document.body.innerHTML = person.name +'今年' + person.age +'岁了'
})
setTimeout(()=>{
    person.age = 31;
},1000)
export function proxyRefs(objectWithRefs){ // 代理的思想,如果是ref 则取ref.value
    return new Proxy(objectWithRefs,{
        get(target,key,receiver){
            let v = Reflect.get(target,key,receiver);
            return v.__v_isRef? v.value:v; 
        },
        set(target,key,value,receiver){ // 设置的时候如果是ref,则给ref.value赋值
            const oldValue = target[key];
            if(oldValue.__v_isRef){
                oldValue.value = value;
                return true
            }else{
                return Reflect.set(target,key,value,receiver)
            }
        }
    })
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值