在 Vue 3 的组合式 API 中,reactive()和ref()都是创建响应式数据的核心 API,但它们的设计目标、适用场景和使用方式有本质区别。
1. 核心定位:处理的数据类型不同
reactive():仅用于包装「对象类型」(包括普通对象、数组、Map、Set 等),返回一个深层响应式的 Proxy 代理对象。它无法直接处理基本类型(如
string、number、boolean),否则会抛出警告且无效。ref():可以包装「任意类型」(基本类型 + 对象类型),返回一个Ref<T>类型的响应式容器(本质是带.value属性的对象)。对于对象类型,
ref()内部会自动调用reactive()将其转换为深层响应式 Proxy。
2. 访问方式:是否需要.value
reactive():直接访问对象的属性(无需额外语法)。示例:
import { reactive } from 'vue' const user = reactive({ name: 'Alice', age: 20 }) console.log(user.name) // 直接访问 → "Alice" user.age++ // 直接修改 → 响应式更新ref():必须通过.value访问或修改内部值(模板中会自动解包,无需写.value)。示例:
import { ref } from 'vue' const count = ref(0) // 包装基本类型 console.log(count.value) // 必须加 .value → 0 count.value++ // 修改值 → 响应式更新 const user = ref({ name: 'Bob' }) // 包装对象类型(内部转 reactive) console.log(user.value.name) // 先 .value 拿到代理对象 → "Bob" user.value.age = 21 // 修改属性 → 响应式更新
3. 赋值行为:能否直接替换整个数据
reactive():不能直接替换整个对象(会丢失响应式)。因为
reactive()返回的是原对象的 Proxy 代理,若直接赋值新对象(如state = { ... }),新对象未被 Proxy 包裹,不再是响应式的。错误示例:
const state = reactive({ count: 0 }) state = { count: 1 } // ❌ 错误:直接替换对象,失去响应式ref():可以直接修改.value(无论基本类型还是对象类型)。因为
ref()的.value是可变的容器,替换.value会触发响应式更新。正确示例:
const count = ref(0) count.value = 1 // ✅ 正确:修改 .value → 响应式更新 const user = ref({ name: 'Tom' }) user.value = { name: 'Jerry' } // ✅ 正确:替换整个对象 → 响应式更新
4. 适用场景:如何选择?
场景 | 推荐 API | 原因 |
|---|---|---|
处理基本类型(数字、字符串、布尔) |
|
|
处理单值对象(如一个配置项) |
| 方便通过 |
处理复杂对象/数组(多属性、嵌套结构) |
| 直接访问属性更简洁,无需 |
需要统一响应式逻辑(全用一种 API) |
| 所有类型都能用 |
5. 模板中的使用差异
reactive():直接在模板中使用代理对象的属性(无需额外处理)。示例:
<template> <div>{{ user.name }} ({{ user.age }})</div> </template> <script setup> import { reactive } from 'vue' const user = reactive({ name: 'Alice', age: 20 }) </script>ref():模板中自动解包(无需写.value),直接用变量名访问。示例:
<template> <div>{{ count }}</div> <!-- 自动解包 count.value --> <div>{{ user.name }}</div> <!-- 自动解包 user.value.name --> </template> <script setup> import { ref } from 'vue' const count = ref(0) const user = ref({ name: 'Bob' }) </script>
补充:toRefs()与reactive()的配合
当需要将reactive()对象的属性解构到组件中时(避免失去响应式),可以用toRefs()将每个属性转为ref:
import { reactive, toRefs } from 'vue' const state = reactive({ count: 0, name: 'Alice' }) const { count, name } = toRefs(state) // 转为 ref 对象 console.log(count.value) // 0(需用 .value 访问)总结:一句话区分
reactive():给对象/数组穿件「响应式外套」,直接摸属性;ref():给任何数据装个「响应式盒子」,开盒子用.value(模板里自动开)。
如果是新手,建议优先用ref()(处理所有类型,避免踩坑);若明确处理复杂对象,用reactive()更简洁。两者可以混合使用,核心是理解它们的响应式边界~
惠州大亚湾