VUE3学习第五天 —深入响应式原理(二)

接下来是响应式的下半场,ref,toRefs, computed,废话不多说进入学习!

ref

分析:

这也是创建响应式对象的函数, 他接收一个参数,可以是原始值也可以是对象,如果是通过ref创建的响应式对象就直接返回,如果是一个普通的对象,内部会调用reactive函数,将基于普通对象创建一个响应式对象。否则会创建一个具有value的响应式对象,并返回。接下来我们来实现它!

代码实现:

export function ref (raw) {
  // 判断raw 是否是ref创建的对象,如果是直接返回
  if(isObject(raw) && raw.__v_isRef) {
    return raw
  }

  // 如果是一个普通对象则convert那里调用reactive,如果是原始类型值直接返回
  let value = convert(raw);
  // 创建一个对象,并添加一个value属性成员,添加get set来做依赖收集和触发更新,生成响应式对象。并做标记是通过ref生成的。
  const result = {
    __v_isRef: true,
    get value () {
      track(result, 'value')
      return value
    },
    set value (newValue) {
      if(newValue !== value) {
        raw = newValue
        value = convert(raw);
        trigger(result, 'value')
      }
    }
  }
  return result
}

复制代码

reactive VS ref

  • ref 可以把基本数据类型数据,转化成响应式对象
    我们可以在代码中可以看到,会将基本数据类型转化成一个有value属性的对象,再将这个对象转化成响应式对象
  • ref 返回的对象,重新赋值成对象也是响应式的
    因为该对象是在ref里面生成的,对象不会变,只是value的属性值发生变化而已
  • reactive 返回的对象,重新赋值丢失响应式
    从第四天的reactive代码中也可以看得出来重新赋值的话就不是proxy代理对象了而是一个普通对象失去响应式
  • reactive 返回的对象不可以结构
    结构出来以后,就不属于这个代理对象的属性,而是一个普通的变量,脱离代理对象,失去get set deleteProperty,失去响应式。

我们自己实现了响应式之后,就很容易明白这些问题,直接在实战场景中学习,会更了解问题的本质。

  • 如果一个对象属性多的时候可以使用reactive,如果一个对象属性少的话最好使用ref,因为这样生成的响应式对象可以结构返回。

toRefs

分析:

  • 这个函数接收一个reactive对象,也就是Proxy对象。如果这个对象不是reactive创建的对象则直接返回。
  • 然后把对象的所有属性转换成一个类似ref返回的对象,把转化后的属性挂载到一个新的对象返回

代码实现:

export function toRefs (proxy) {
  const ret = proxy instanceof Array ? new Array(proxy.length) : {}

  for(const key in proxy) {
    ret[key] = toProxyRef(proxy, key)// 返回类似的ref对象,没有进行依赖收集
  }
  return ret
}

function toProxyRef (proxy, key) {
  const r = {
    __v_isRef: true,
    get value () {
      // 这里不需要去收集依赖,因为这里会有自身的proxy里面去收集
      return proxy[key] // 当这样访问proxy对象的key属性时就会触发proxy对象依赖收集
    },
    set value(newValue) {
      proxy[key] = newValue // 这设置值的时候也会触发proxy key的更新
    }
  }
  return r
}

复制代码

computed

computed需要就收一个有返回值的函数作为参数,这个函数的返回值就是计算属性的值,并且要监听这个函数里面响应式数据的变化,最后把这个函数执行结果返回。

export function computed (getter) {
  const result = ref();
  effect(() => (result.value = getter()))

  return result
}
// 使用
let total = computed(() => {
  return price.value * count.value
})
console.log(total.value)

复制代码

总结

到这里,我们模拟了vue3 响应式系统中的reactive,ref, toRefs, computed的内部实现,还实现了依赖收集,和触发更新的track, trigger, effect 比较底层的函数,一般情况下我们不会去调用。希望这两篇文章对vue3响应式原理有个大概的了解,欢迎评论区讨论,下面会贴上代码!

[模式实现源码](github.com/zelixag/vue…

© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享