Vue3.0中reactive 嵌套 ref 的反直觉现象

1,646 阅读3分钟

反直觉的现象

在 Vue 3 中,使用 reactive 和 ref 来创建响应式数据是常见的做法。然而,它们在嵌套使用时,可能会导致一些反直觉的现象。

具体来说,当将一个 ref 对象作为另一个 reactive 对象的属性值时,直接访问该 ref 对象的值可能会出现一些反直觉的行为。这是因为 ref 对象本身是一个包装器,用于给基本类型的值提供响应式能力。

以下是一个示例来说明这种反直觉现象:

import { reactive, ref } from 'vue';

const data = reactive({
  count: ref(0)
});

console.log(data.count); // 输出的是 ref 对象而不是它的值
console.log(data.count.value); // 输出正确的值

在上述示例中,我们创建了一个嵌套结构的响应式对象 data,其中包含一个 ref 对象作为属性 count 的值。然后,当我们直接访问 data.count 时,输出的是 ref 对象本身,而不是它的值。要获取正确的值,需要使用 data.count.value 来访问 ref 对象的实际值。

这种反直觉的现象是由于 Vue 3 对于 ref 对象的访问方式进行了优化,以提升性能。当使用 ref 对象直接作为响应式对象的属性值时,Vue 3 不会自动解包 ref,而是直接返回 ref 对象本身。这意味着我们需要显式地使用 .value 来访问 ref 对象的值。

可能会遇到的问题

当在 Vue 3 中将 ref 对象嵌套在 reactive 对象中时,可能会遇到以下问题:

  1. 无法正确跟踪更改: reactive 只能追踪对象属性的更改,而无法追踪 ref 对象本身的更改。这意味着当 ref 对象的值发生变化时,父级的 reactive 对象将不会自动更新。
  2. 访问值的问题: 直接访问嵌套的 ref 对象,将返回 ref 包装器本身而不是它的值。这可能导致意外的结果,因为我们可能期望获取 ref 对象的实际值。

以下是一个代码示例,展示了在嵌套 ref 的情况下可能出现的问题:

import { reactive, ref } from 'vue';

const data = reactive({
  count: ref(0)
});

console.log(data.count); // 输出的是 ref 对象而不是它的值
console.log(data.count.value); // 输出正确的值

data.count.value = 1; // 通过 ref.value 修改值

console.log(data.count.value); // 输出 1
console.log(data.count); // 输出 ref 对象而不是它的值

在上述示例中,我们创建一个 reactive 对象 data,其中的属性 count 是一个 ref 对象。当我们直接访问 data.count 时,输出的是 ref 对象本身而不是它的实际值。要获取值,需要使用 data.count.value

此外,如果我们通过 data.count.value 修改 ref 的值,父级的 reactive 对象将不会自动更新。

为了解决这些问题,可以考虑以下的解决方案:

  1. 如果需要在 reactive 对象中使用响应式的基本类型值,可以使用 ref 将整个对象包装起来,而不是仅包装其中的属性。
  2. 在模板中,应使用 .value 访问嵌套的 ref 对象的实际值。

例如,在上述示例中,我们可以将 count 本身改为 ref,然后访问值时省略 .value

import { reactive, ref } from 'vue';

const count = ref(0);

const data = reactive({
  count: count
});

console.log(data.count); // 输出的是 ref 对象而不是它的值
console.log(data.count.value); // 输出正确的值

data.count = 1; // 修改 ref 的值

console.log(data.count); // 输出 1
console.log(data.count.value); // 输出 1

为了避免混淆和错误,建议在访问嵌套的 ref 对象时,始终使用 .value 来获取其真实的值。