美文网首页
Vue3.0 响应式原理

Vue3.0 响应式原理

作者: A_走在冷风中 | 来源:发表于2021-10-19 23:44 被阅读0次

    Vue3 使用 Proxy 对象重写响应式系统,这个系统主要有以下几个函数来组合完成的:

    1、reactive:
    接收一个参数,判断这参数是否是对象。不是对象则直接返回这个参数,不做响应式处理
    创建拦截器对象 handler, 设置 get/set/deleteProperty
    get
    收集依赖(track)
    返回当前 key 的值。
    如果当前 key 的值是对象,则为当前 key 的对象创建拦截器 handler, 设置 get/set/deleteProperty
    如果当前的 key 的值不是对象,则返回当前 key 的值
    set
    设置的新值和老值不相等时,更新为新值,并触发更新(trigger)
    deleteProperty
    当前对象有这个 key 的时候,删除这个 key 并触发更新(trigger)
    返回 Proxy 对象
    2、effect: 接收一个函数作为参数。作用是:访问响应式对象属性时去收集依赖
    3、track:
    接收两个参数:target 和 key
    如果没有 activeEffect,则说明没有创建 effect 依赖
    如果有 activeEffect,则去判断 WeakMap 集合中是否有 target 属性,
    WeakMap 集合中没有 target 属性,则 set(target, (depsMap = new Map()))
    WeakMap 集合中有 target 属性,则判断 target 属性的 map 值的 depsMap 中是否有 key 属性
    depsMap 中没有 key 属性,则 set(key, (dep = new Set()))
    depsMap 中有 key 属性,则添加这个 activeEffect
    4、trigger:
    判断 WeakMap 中是否有 target 属性
    WeakMap 中没有 target 属性,则没有 target 相应的依赖
    WeakMap 中有 target 属性,则判断 target 属性的 map 值中是否有 key 属性,有的话循环触发收集的 effect()

    //判断是否是对象
    const isObject = (val) => val != null && typeof val === 'object'
    
    //判断是否是对象,如果是对象继续调用reactive转换成响应式对象
    const convert = (target) => (isObject(target) ? reactive(target) : target)
    
    const hasOwnProperty = Object.prototype.hasOwnProperty
    //判断对象中是否有某个属性
    const hasOwn = (target, key) => hasOwnProperty.call(target)
    
    ##手写核心响应式原理
    
    /**
     *  接收一个参数,判断这个参数是否是对象
     *  创建拦截器对象handler,设置get/set/deleteProperty
     *  返回Proxy对象
     */
    export function reactive(target) {
      //判断target是否是对象,不是对象直接返回
      if (!isObject(target)) return
      //创建拦截器对象handler
      const handler = {
        get(target, key, receiver) {
          //收集依赖
          track(target, key)
          const result = Reflect.get(target, key, receiver)
          //如果result是对象继续调用reactive转换成响应式对象
          return convert(result)
        },
        set(target, key, value, receiver) {
          //获取属性值
          const oldValue = Reflect.get(target, key, receiver)
          let result = true
          //判断新值是否等于旧值
          if (oldValue !== value) {
            // 如果相等,调用set修改属性值
            result = Reflect.set(target, key, value, receiver)
            //触发更新
            trigger(target, key)
          }
          return result
        },
        deleteProperty(target, key) {
          //判断target中是否有自己的key属性
          const hasKey = hasOwn(target, key)
          const result = Reflect.deleteProperty(target, key)
          if (hasKey && result) {
            //target中有key属性且删除成功
            //触发更新
            trigger(target, key)
          }
          return result
        },
      }
    
      //返回代理对象
      return new Proxy(target, handler)
    }
    
    let activeEffect = null
    //接收一个函数作为参数
    export function effect(callback) {
      activeEffect = callback
      callback() //访问响应式对象属性,去收集依赖
      activeEffect = null
    }
    
    //定义一个map 存储依赖
    let targetMap = new WeakMap()
    //接收两个参数 目标对象target 要跟踪的属性key
    export function track(target, key) {
      if (!activeEffect) return
      let depsMap = targetMap.get(target)
      //判断depsMap 是否有值,没有的话就创建一个,存储到targetMap
      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) {
      //去depsMap中查找target
      const depsMap = targetMap.get(target)
      //如果没有找到直接返回
      if (!depsMap) return
    
      //查找dep集合
      const dep = depsMap.get(key)
      if (dep) {
        //找到dep中的每一个函数,调用effect
        dep.forEach((effect) => {
          effect()
        })
      }
    }
    
    //定义一个响应式属性
    export function ref(raw) {
      //判断raw是否是ref创建的对象, 如果是直接返回
      if (isObject(raw) && raw.__v__isRef) return
      let value = convert(raw)
      //创建ref对象
      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) {
      //判断proxy 是否是reactive创建的
      //判断proxy是否是数组
      const ret = proxy instanceof Array ? new Array(proxy.length) : {}
      for (const key in proxy) {
        //将每一个属性都转换成ref属性
        ret[key] = toProxyRef(proxy, key)
      }
      return ret
    }
    
    //将属性转换成ref
    function toProxyRef(proxy, key) {
      const r = {
        __v__isRef: true,
        get value() {
          //无需收集依赖, proxy对象内部会收集
          return proxy[key]
        },
        set value(newValue) {
          proxy[key] = newValue
        },
      }
      return r
    }
    
    //computed 需要接收一个有返回值函数作为参数
    //这个函数的返回值就是计算属性的值
    export function computed(getter) {
      const result = ref()
      //将getter的返回值存入result中
      effect(() => {
        result.value = getter()
      })
      return result
    }
    
    
    

    相关文章

      网友评论

          本文标题:Vue3.0 响应式原理

          本文链接:https://www.haomeiwen.com/subject/xsgxaltx.html