在 Vue 3 的 Composition API 里,reactive()
和 ref()
都是用来把「普通数据」变成「响应式数据」的函数。
一句话区别:
reactive()
只能包裹对象/数组;ref()
可以包裹任何类型,但在 模板 里读取时,不需要.value
。
下面按「概念 → API → 使用 → 常见注意点」展开。
1. 为什么需要它们
Vue 2 里只有 data() { return {...} }
这一种声明响应式数据的方式。
Vue 3 的 Composition API 把「声明响应式」拆成了两个底层函数:
函数 | 适合场景 | 返回值 |
---|---|---|
reactive() |
对象、数组 | Proxy |
ref() |
基本类型、对象、数组 | RefImpl 对象 |
2. reactive() 用法
import { reactive } from 'vue'
const state = reactive({
count: 0,
list: [1, 2, 3]
})
// 使用
state.count++ // ✅ 触发视图更新
state.list.push(4) // ✅ 触发视图更新
- 模板里直接写:
<template>
<p>{{ state.count }}</p>
<button @click="state.count++">+</button>
</template>
⚠️ 注意
- 不能对
state
重新赋值(会失去响应式)
state = { count: 10 } // ❌ 错误
- 解构会丢失响应式
const { count } = state // ❌ count 不是响应式
// 正确:用 toRefs(state) 解构
3. ref() 用法
import { ref } from 'vue'
const count = ref(0)
const name = ref('Vue')
const obj = ref({ a: 1 }) // 也可以包对象
- 脚本里取值 / 赋值 必须加
.value
count.value++ // ✅
obj.value.a = 2 // ✅
- 模板里会自动解包,不写
.value
<template>
<p>{{ count }}</p> <!-- 模板里直接写 count -->
<button @click="count++">+</button>
</template>
⚠️ 注意
- 重新赋值不会破坏响应式
count.value = 100 // ✅ 仍是响应式
- 对对象/数组用
ref()
时,深层属性依旧是响应式,因为内部会递归reactive()
。
4. 什么时候用哪个?
场景 | 推荐 |
---|---|
需要一组关联属性(表单、状态对象) | reactive() |
只有一个基本类型(数字、布尔、字符串) | ref() |
需要解构或重新赋值(替换整个对象) | ref() |
需要深层响应式且结构固定 | reactive() |
5. 组合使用示例
<script setup>
import { reactive, ref } from 'vue'
// 一整个对象
const user = reactive({
name: 'Tom',
age: 18
})
// 单个值
const loading = ref(false)
// 方法
function addAge() {
user.age++
loading.value = true
}
</script>
<template>
<div v-if="!loading">
{{ user.name }} - {{ user.age }}岁
<button @click="addAge">长大一岁</button>
</div>
<p v-else>加载中...</p>
</template>
6. 速记口诀
- 对象用
reactive
,基本类型用ref
。 - 模板里
ref
省.value
,脚本里千万别省。 - 解构对象用
toRefs()
,重新赋值用ref()
。