Ref 与reactive
在 Vue 3 中,reactive
和 ref
是用于创建响应式数据的两个不同的 API。它们都是 Vue 3 Composition API 的一部分。
ref
:
ref
用于创建一个包装基本数据类型的响应式对象。它接受一个初始值,并返回一个包含 value
属性的对象。ref
主要用于包装基本数据类型,如数字、字符串等。
import { ref } from 'vue'; const count = ref(0); // 读取值 console.log(count.value); // 输出: 0 // 修改值 count.value += 1; console.log(count.value); // 输出: 1
reactive
:
reactive
用于创建一个包装普通对象的响应式对象。它接受一个普通对象,并返回一个代理对象,该代理对象中的属性都是响应式的。
import { reactive } from 'vue'; const user = reactive({ name: 'John', age: 30, }); // 读取值 console.log(user.name); // 输出: John // 修改值 user.age += 1; console.log(user.age); // 输出: 31
区别:
- 「数据类型:」
ref
主要用于包装基本数据类型,如数字、字符串等。reactive
主要用于包装普通对象。
- 「访问属性:」
- 在
ref
中,你需要通过.value
访问和修改值。 - 在
reactive
中,直接访问和修改对象的属性即可。
- 「用例:」
ref
通常用于单一值,如计数器、标志等。reactive
通常用于包装对象,用于表示具有多个属性的数据。
import { ref, reactive } from 'vue'; // 使用 ref const count = ref(0); count.value += 1; // 使用 reactive const user = reactive({ name: 'John', age: 30, }); user.age += 1;
为什么同时存在 ref()、reactive()?
ref
和 reactive
虽然都用于创建响应式对象,但它们在设计和用途上有一些区别,适用于不同的场景。理解这些差异有助于更好地选择合适的 API。
- 「单一值 vs. 对象:」
const count = ref(0); // 单一值 const user = reactive({ name: 'John', age: 30 }); // 对象
ref
主要用于包装基本数据类型,如数字、字符串等,以及需要单一值的情况。reactive
用于包装普通对象,对于需要表示多个属性的数据结构。
- 「访问方式:」
// 使用 ref count.value += 1; // 使用 reactive user.age += 1;
- 在
ref
中,你需要通过.value
访问和修改值。 - 在
reactive
中,直接访问和修改对象的属性即可。
- 「响应式原理:」
ref
通过 Vue 3 提供的ref
函数实现,它为基本数据类型提供了轻量级的响应式封装。reactive
通过 Vue 3 提供的reactive
函数实现,它使用 Proxy 对象来实现对整个对象的深层次响应式封装。
- 「用例和场景:」
ref
适用于简单的值或在模板中需要直接使用的值。reactive
适用于表示复杂数据结构,需要处理多个属性的情况,尤其是在逻辑层面需要进行深层次的数据操作时。
import { ref, reactive } from 'vue'; // 使用 ref const count = ref(0); count.value += 1; // 使用 reactive const user = reactive({ name: 'John', age: 30 }); user.age += 1;
虽然在某些简单的场景中使用 ref
就足够了,但当处理更复杂的数据结构时,尤其是需要进行深层次的数据操作时,reactive
提供了更强大的功能。选择使用哪个 API 取决于你的具体需求和项目的复杂性。
ref与普通变量的区别
ref
在 Vue 3 的 Composition API 中被引入,它主要用于创建响应式对象,尤其是用于包装基本数据类型的响应式对象。相比于普通变量,ref
具有一些特别的支持和行为:
- 「响应式变化检测:」
ref
创建的对象是响应式的,意味着当其值发生变化时,相关的视图会进行更新。- 普通变量在 Vue 2 中没有内置的响应式支持,需要使用
Object.defineProperty
或Vue.set
手动进行响应式处理。
- 「
.value
访问和修改:」
- 在使用
ref
创建的响应式对象中,需要通过.value
访问和修改值。 - 这是因为
ref
的设计初衷是为了确保在模板中使用变量时能够区分变量本身和它的值。因此,直接操作ref
对象会导致一些问题,必须使用.value
。
const count = ref(0); console.log(count.value); // 读取值 count.value += 1; // 修改值
- 「自动解包:」
- 在模板中使用
ref
变量时,Vue 3 会自动解包,直接访问变量值,而不需要显式使用.value
。 - 这样可以在模板中获得更自然的语法。
<!-- 在模板中自动解包 --> <template> <div>{{ count }}</div> </template>
- 「
ref
函数:」
ref
函数是 Vue 3 提供的 API,用于创建一个包装基本数据类型的响应式对象。这个函数的使用方式使得 Vue 能够更轻松地追踪数据的变化。- 普通变量在 Vue 2 中不具备这种直接的响应式支持,需要额外的处理来使其响应式。
「注意」在 Vue 3 中当你将 ref
对象传递到模板(<template>
)中时,会自动解包,无需额外使用 .value
。这是 Vue 3 的一个改进,旨在提供更自然的语法。
以下是一个示例,演示了在模板中传递和使用 ref
对象的情况:
<!-- ParentComponent.vue --> <template> <div> <p>Parent Component: {{ myRef }}</p> <ChildComponent :childRef="myRef" /> </div> </template> <script> import { ref } from 'vue'; import ChildComponent from './ChildComponent.vue'; export default { components: { ChildComponent, }, setup() { const myRef = ref('Hello from Parent'); return { myRef, }; }, }; </script>
<!-- ChildComponent.vue --> <template> <div> <p>Child Component: {{ childRef }}</p> <button @click="updateValue">Update in Child</button> </div> </template> <script> import { defineComponent } from 'vue'; export default defineComponent({ props: { childRef: { type: Object, required: true, }, }, methods: { updateValue() { // 在子组件中通过 .value 修改值 this.childRef.value = 'Updated in Child'; }, }, }); </script>
小结
到底选择哪个要综合考虑你的数据结构和使用场景,选择适当的响应式 API。在实际开发中,你可能会同时使用 ref 和 reactive,根据不同的情况选择不同的响应式对象。