likes
comments
collection
share

新手学Vue3(五)reactive VS ref 之区别与关系

作者站长头像
站长
· 阅读数 16

Vue3 刚出 bata 版的时候,就有高手聊 ref 和 reactive,可能那时候由于某种原因吧,流传出来一种说法: ref 是用 reactive 实现的。这个。。。

我以为这么多年过去了,大家应该都可以正确理解 ref 和 reactive 了,结果,看了一些人的评论,似乎还是比较模糊。

我们用最简洁的方式来说清楚。

基础类型

我们先来看看基础类型的情况:(string、number、bool、bigint 等)

const foo1 = ref('123')
foo1.value = '456'

const foo2 = reactive({value: '123'})
foo2.value = '456'

对比一下基础类型的 ref 和 reactive,从使用角度来说似乎差不多,那么内部结构呢?

  1. 内部结构一样
  2. 内部结构不一样
  • 我们看看打印结果:

新手学Vue3(五)reactive VS ref 之区别与关系

左面是 reactive,右面是 ref,事实胜于雄辩,内部结构完全不一样。

对于基础类型的 ref,那是和 reactive 一点关系都没有。

对象类型

我们再来对比一下对象(包括数组、Set等)的情况:

const foo1 = ref({name:'ref'})

const foo2 = ref(reactive({name:'reactive'})

新手学Vue3(五)reactive VS ref 之区别与关系

内部结构完全一样,这说明:如果传入一个对象,不管我们用没用 reactive,ref 都会给套上 reactive。

引用类型(对象、数组等)的 ref,会先套上 reactive,然后再交给 value 属性。

ref 的本质

ref 是 class 的实例,源码可证明:

新手学Vue3(五)reactive VS ref 之区别与关系

首先定义一个名为 RefImpl 的 class,然后创建一个 createRef 的函数,最后是 ref 函数。

  • RefImpl 是一个class,有一个 value 的属性(get、set)。
  • createRef 是一个语法糖,负责检查类型和生成 class 的实例。
  • ref 是深层响应。
  • shallowRef 是浅层响应。

构造函数和 set 里使用 toReactive 把对象变成 reactive 的形式,下面是源码:

const toReactive = (value) => isObject(value) ? reactive(value) : value;

reactive 的本质是 Proxy

看看结构(第一张图左面那个)就知道了,很明显的 Proxy 结构。

为啥有了 reactive 还要弄个 ref 呢?还不是因为 Proxy 不支持基础类型,而 Vue 又不想使用 reactive({value: xxx}) 的方式实现基础类型的响应需求。于是有了 ref。

使用 ref 还是 reactive?

这个,看大家喜欢吧。

如果公司有规定,那么按照公司规范;如果公司没有细节要求,那么你开心就好

我知道大家喜欢无脑 ref ,是因为可以直接赋值(而不失去响应性),但是真的如此吗?

const foo3 = ref({
  name:'ref'
})
const foo5 = reactive({
  person: {
    name:'reactive'
  }
})

foo3.value = {
  name: '新名字-ref'
}

foo5.person = {
  name: '新名字-reactive'
}

两种方式都不会失去响应性,使用 reactive,需要多一层,而 ref 自动封了一层(定义的时候简单了),但是使用 ref 还是需要.value (听说有插件可以不写.value了)。

但是前提是不能解构。

let { value } = foo3
let { person } = foo5
const change = () => {
  value = { name: 'change改变的'}
  person = {name: 'change改变的22'}
}

解构之后再整体赋值,依然没有响应性。所以,你想怎么用都行。

小结

  • ref 的本质是 class,用 get、set 实现 value 属性的访问拦截。
  • 基础类型的 ref, 和 reactive 没有任何关系。
  • 引用类型的 ref,在初始化(构造函数)和 set 的时候,套上了 reactive。