Vue.js 3.0响应式系统原理

一、响应式系统原理 - 介绍

  • Proxy对象实现属性监听
  • 默认监听动态添加的属性
  • 默认监听属性的删除操作
  • 默认监听数组索引和 length属性
  • 可以作为单独的模块使用
  • 多层属性嵌套,在访问属性过程中处理下一级属性

核心方法

  • reactive/ref/toRefs/computed
  • effect(watch和watchEffect是vue的runtime.core中实现的。watch函数内部其实使用了就是这个effect底层函数)
  • track(vue3中收集依赖的函数)
  • trigger(vue3中触发更新的函数)

二、响应式系统原理-Proxy对象回顾

  • set 和 deleteProperty 中需要返回布尔类型的值
    • 在严格模式下,如果返回 false 的话,会出现 Type Error 的异常
  • Proxy 和 reflect 中使用 receiver
    • Proxy中receiver:Proxy或者继承Proxy的设置
    • Reflect中 receiver:如果 target 对象设置了 getter,getter 中的 this 指向 receiver

三、响应式系统原理-reactive

• 接收一个参数,判断这参数是否是对象
• 创建拦截器对象handler,设置get/set/deleteProperty
• 返回Proxy对象

四、响应式系统原理-收集依赖

Vue.js 3.0响应式系统原理_第1张图片

reactive vs ref
• ref可以把基本数据类型数据,转成响应式对象
当获取数据时要使用value属性,模板中使用时可以使用value
reactive不能把基本数据类型数据,转成响应式对象
• ref返回的对象,重新赋值成对象也是响应式的
• reactive返回的对象,重新赋值丢失响应式
因为重新赋值的对象不再是代理对象
• reactive返回的对象不可以解构
如果要想解构的话需要使用toRefs来处理reactive返回的这个对象

toRefs函数接收一个reactive返回的响应式对象也就是一个proxy对象。如果传入的参数不是reactive创建的响应式对象 直接返回。然后再把传入对象的所有属性转换成一个类似于ref返回的对象,把转换后的属性挂载到一个新的对象上返回

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)
      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)
      }
      return result
    },
    deleteProperty (target, key) {
     
      const hadKey = hasOwn(target, key)
      const result = Reflect.deleteProperty(target, key)
      if (hadKey && result) {
     
        // 触发更新
        trigger(target, 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
}

你可能感兴趣的:(笔记)