Vue3 响应性基础 API --reactive

基本用法

  • 返回对象的响应式副本,只能代理对象,不能代理普通值
const obj = reactive({count: 0, name: 'hyh'})

const count = reactive(1)
// value cannot be made reactive: 1
  • 响应式转换是“深层”的——它影响所有嵌套 property
const obj = reactive({count: 0, name: 'hyh', info: { age: 25 }})

console.log(obj.count)  // 0
console.log(obj.info.age) // 25
  • reactive 将解包所有深层的 refs,同时维持 ref 的响应性。
const count = ref(1)
const obj = reactive({ count })

// ref 会被解包
console.log(obj.count === count.value) // true

// 它会更新 `obj.count`
count.value++
console.log(count.value) // 2
console.log(obj.count) // 2

// 它也会更新 `count` ref
obj.count++
console.log(obj.count) // 3
console.log(count.value) // 3
  • 当将 ref 分配给 reactive property 时,ref 将被自动解包。
const count = ref(1)
const obj = reactive({})

obj.count = count

console.log(obj.count) // 1
console.log(obj.count === count.value) // true

实现原理

reactive 是基于 Proxy 实现的响应式。


const ReactiveFlags = {
  SKIP = '__v_skip',
  IS_REACTIVE = '__v_isReactive',
  IS_READONLY = '__v_isReadonly',
  RAW = '__v_raw'
}

// 用于缓存代理过的对象
const proxyMap = new WeakMap();

function createGetter(isReadonly = false, shallow = false){
    return function get(target, key, receiver){
        // 判断代理对象是否为数组
        const targetIsArray = isArray(target);
        if(targetIsArray && hasOwn(arrayInstrumentations, key)){
            // 如果是特殊方法,没有进行依赖收集, 而是重写了一些方法
            return Reflect.get(arrayInstrumentations, key, receiver)
        }
        
        // 获取到目标属性的值    
        const res = Reflect.get(target, key, receiver);

        if(!isReadonly){
            // 如果不是只读的属性, 当获取属性值的时候进行依赖收集
            track(target, 'get', key)
        }

        // 如果只是浅层的 shallowReactive() shallReadonly()
        if (shallow) {
            return res;
        }

        if(isRef(res)){
            // 判断是否需要解包
            // ref unwrapping - does not apply for Array + integer key. 
            const shouldUnwarp = !targetIsArray || !isIntegerKey(key)
            return shouldUnwarp ? res.value : res;
        }

        // 这里只有在用户取值的时候才会去对嵌套的对象进行响应式处理,相当于懒处理
        if(isObject(res)){
            return isReadonly ? readonly(res) : reactive(res)
        }

        return res
    }
}

function createSetter(shallow = false){
    return function set(target, key, value, receiver){
        const oldValue = target[key]

        const hadKey = hasOwn(target, key)

        const res = Reflect.set(target, key, value, receiver);

        // 触发effect更新
        if(!hadKey){
            trigger(target, 'add', key, value)
        }else{
            trigger(target, 'set', key, value, oldValue)
        }

    }
}

function mutableHandler(){
    get: createGetter(),
    set: cerateSetter(),

}

function reactive(target){

    // 针对特殊场景 reactive(readonly(obj))-> 直接返回readonly即可
    if(target && target[ReactiveFlags.IS_READONLY]){
        return target
    }
    return createReactiveObject(target, false, mutaleHandler)
}

function createReactiveObject(target, isReadonly, baseHandler){
    if(!isObject(target)){
        if (__DEV__) {
            console.warn(`value cannot be made reactive: ${String(target)}`)
        }
        return target
    }

    // target already has corresponding Proxy
    const existingProxy = proxyMap.get(target) // 看目标是否被代理过
    if (existingProxy) { // 如果代理过,直接返回代理过的对象
        return existingProxy
    }

    const proxy = new Proxy( // 创建一个proxy对象
        target,// 调用对应的handler进行代理
        targetType: baseHandlers
    )
    proxyMap.set(target, proxy) // 存到缓存中
    return proxy
}

以上代码只是Vue3的部分源码,简单的实现了reactive的响应式原理。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值