vue3.0响应式原理

16 篇文章 0 订阅
  • proxy对象实现属性监听

  • 多层次属性嵌套,在访问属性过程中处理下一级属性

  • 默认监听动态添加的属性

  • 默认监听数组索引和length属性

  • 可以作为单独的模块使用

核心方法

  • Reactive/ref/toRefs/computed

  • effect

  • track

  • trigger

Reactive函数

  • 接收一个参数,判断这参数是否是对象

  • 创建拦截器对象handler,设置get/set/deleteProperty

  • 返回Proxy对象

Reactive代码示例

export function reactive(target) {
    if (!isObject(target)) return target

    const handler = {
        get(target, key, receiver) {
            //收集依赖
            track(target, key)
           // console.log('get', key)
            const result = Reflect.get(target, key, receiver)
            return convert(result)

        },
        set(target, key, value, receiver) {

            const oldValue = Reflect.get(target, key, receiver)
            let result = true
            if (oldValue !== value) {
                result = Reflect.set(target, key, value, receiver)
                //触发更新
                trigger(target,key)
                //console.log('set', key, value)
            }

            return result
        },
        deleteProperty(target, key) {
            const hadkey = hasOwn(target, key)
            const result = Reflect.deleteProperty(target, key)
            if (hadkey && result) {
                //  触发更新
                trigger(target,key)
           //     console.log('delete', key)
            }
            return result
        }
    }
    return new Proxy(target, handler)
}

effect代码示例

let activeEffect = null
export function effect(callback) {
    activeEffect = callback
    callback()//访问响应式对象属性,去收集依赖
    activeEffect = null
}

track代码示例

let targetMap = new WeakMap()
export function track(target, key) {
    if (!activeEffect) return
    let depsMap = targetMap.get(target)
    if (!depsMap) {
        targetMap.set(target, (depsMap = new Map()))
    }
    let dep = depsMap.get(key)
    if (!dep) {
        depsMap.set(key, (dep = new Set()))
    }
    dep.add(activeEffect)
}

tigger代码示例

export function trigger(target, key) {
    const depsMap = targetMap.get(target)
    if (!depsMap) return
    const dep = depsMap.get(key)
    if(dep){
        dep.forEach(effect=>{
            effect()
        })
    }
}

收集依赖

Reactive 和 ref的区别

  • ref可以把基本数据类型数据,转成响应式对象

  • ref返回的对象,重新赋值成对象也是响应式的

  • reactive返回的对象,重新赋值丢失响应式

  • reactive返回的对象不可以解构

reactive的页面实现

     import { reactive,effect } from './reactivity/index.js'
     
     const product=reactive({
         name:'iphone',
         price:'5800',
         count:3
     })
     let total=0
     effect(()=>{
         total=product.price*product.count
     })
     console.log('1:'+total)

     product.price=4000
     console.log('2:'+total)
     
     product.count=1
     console.log('3:'+total)

ref的页面实现

import { reactive,effect,ref } from './reactivity/index.js'
     
 
    const price=ref(5000)
    const count=ref(3)
     let total=0
     effect(()=>{
         total=price.value*count.value
     })
     console.log('1:'+total)

     price.value=4000
     console.log('2:'+total)
     
     count.value=1
     console.log('3:'+total)

如果一个对象成员多的时候使用ref不方便,因为要总要加value,如果只有一个响应式数据的时候用ref,可以直接解构返回

Torefs页面的实现

  import { reactive,effect,toRefs } from './reactivity/index.js'
     
     function useProduct(){
        const product=reactive({
         name:'iphone',
         price:'5800',
         count:3
     })

     return toRefs(product)
     }
    
     const { price,count }=useProduct()

     let total=0
     effect(()=>{
         total=price.value*count.value
     })
     console.log('1:'+total)

    price.value=4000
     console.log('2:'+total)
     
     count.value=1
     console.log('3:'+total)

Torefs把reactive返回的对象的每一个属性转换成类似ref返回的对象,可以对reactive返回的对象进行解构

index.js的代码

const isObject = val => val != null && typeof val === 'object'
const convert = target => isObject(target) ? reactive(target) : target
const hasOwnProperty = Object.prototype.hasOwnProperty
const hasOwn = (target, key) => hasOwnProperty.call(target, key)

export function reactive(target) {
    if (!isObject(target)) return target

    const handler = {
        get(target, key, receiver) {
            //收集依赖
            track(target, key)
           // console.log('get', key)
            const result = Reflect.get(target, key, receiver)
            return convert(result)

        },
        set(target, key, value, receiver) {

            const oldValue = Reflect.get(target, key, receiver)
            let result = true
            if (oldValue !== value) {
                result = Reflect.set(target, key, value, receiver)
                //触发更新
                trigger(target,key)
                //console.log('set', key, value)
            }

            return result
        },
        deleteProperty(target, key) {
            const hadkey = hasOwn(target, key)
            const result = Reflect.deleteProperty(target, key)
            if (hadkey && result) {
                //  触发更新
                trigger(target,key)
           //     console.log('delete', key)
            }
            return result
        }
    }
    return new Proxy(target, handler)
}

let activeEffect = null
export function effect(callback) {
    activeEffect = callback
    callback()//访问响应式对象属性,去收集依赖
    activeEffect = null
}

let targetMap = new WeakMap()
export function track(target, key) {
    if (!activeEffect) return
    let depsMap = targetMap.get(target)
    if (!depsMap) {
        targetMap.set(target, (depsMap = new Map()))
    }
    let dep = depsMap.get(key)
    if (!dep) {
        depsMap.set(key, (dep = new Set()))
    }
    dep.add(activeEffect)
}

export function trigger(target, key) {
    const depsMap = targetMap.get(target)
    if (!depsMap) return
    const dep = depsMap.get(key)
    if(dep){
        dep.forEach(effect=>{
            effect()
        })
    }
}

export function ref(raw){
    // 判断raw是否是ref创建的对象,如果是的话直接返回
    if(isObject(raw)  &&raw._v_isRef){
        return
    }
    let value=convert(raw)
    const r={
      _v_isRef:true,
      get value(){
       track(r,value)
       return value
      },
      set value(newValue){
       if(newValue!==value){
           raw=newValue
           value=convert(raw)
           trigger(r,'value')
       }
      }
    }
    return r

}

export function toRefs(proxy){
    const ret =proxy instanceof Array?new Array(proxy.length):{}
    for(const key in proxy){
      ret[key]=toProxyRef(proxy,key)
    }

    return ret
}

function toProxyRef (proxy, key) {
    const r = {
      __v_isRef: true,
      get value () {
        return proxy[key]
      },
      set value (newValue) {
        proxy[key] = newValue
      }
    }
    return r
  }
  

export function computed(getter){
    const result =ref()

    effect(()=>(result.value=getter()))

    return result

}

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值