响应式基础(上)
本教程共 40 篇 · 第 4 篇 · 更新于 2026-07-29 · 约 8 分钟阅读
4. 响应式基础(上)
本节目标:掌握 ref() 和 reactive() 两种声明响应式状态的方式,理解它们的原理和适用场景。
ref() —— 声明响应式状态的首选
Composition API 推荐用 ref() 来声明响应式状态:
import { ref } from 'vue'
const count = ref(0)
ref() 把参数包成一个带 .value 属性的 ref 对象:
const count = ref(0)
console.log(count) // { value: 0 }
console.log(count.value) // 0
count.value++
console.log(count.value) // 1
在模板中使用
要在模板里用 ref,从 setup() 返回它:
import { ref } from 'vue'
export default {
setup() {
const count = ref(0)
return { count }
}
}
<div>{{ count }}</div>
注意:在模板里用 ref 不需要 .value。Vue 会自动解包。
也可以在事件处理器里直接改:
<button @click="count++">{{ count }}</button>
<script setup> 简化写法
手动返回状态和方法比较啰嗦。用单文件组件的 <script setup> 可以省掉这些:
<script setup>
import { ref } from 'vue'
const count = ref(0)
function increment() {
count.value++
}
</script>
<template>
<button @click="increment">{{ count }}</button>
</template>
<script setup> 里声明的顶层变量、函数自动暴露给模板。
为什么需要 ref
你可能会问:为什么不直接用普通变量?
因为普通变量的读写 Vue 无法追踪。ref() 的 .value 属性给了 Vue 拦截读写操作的机会——getter 里做依赖追踪,setter 里触发更新。
概念上可以把 ref 想象成这样:
// 伪代码,不是真实实现
const myRef = {
_value: 0,
get value() {
track() // 追踪依赖
return this._value
},
set value(newValue) {
this._value = newValue
trigger() // 触发更新
}
}
ref 的另一个好处:可以传给函数同时保留响应式连接,这对逻辑复用很有用。
reactive() —— 让对象本身响应式
另一种声明响应式状态的方式是 reactive():
import { reactive } from 'vue'
const state = reactive({ count: 0 })
和 ref() 不同,reactive() 让对象本身变成响应式的,不需要 .value:
<button @click="state.count++">
{{ state.count }}
</button>
reactive 对象是 JavaScript Proxy,表现得像普通对象,但 Vue 能拦截所有属性的读写。
reactive() 的局限
reactive() 有几个需要注意的限制:
1. 只支持对象类型
不能持有原始类型(string、number、boolean),只对对象、数组、Map、Set 等有效。
2. 不能替换整个对象
Vue 的响应式追踪基于属性访问,必须保持同一个对象引用。替换整个对象会丢失响应式连接:
let state = reactive({ count: 0 })
// 上面那个引用不再被追踪了!
state = reactive({ count: 1 })
3. 解构会丢失响应式
把 reactive 对象的属性解构到本地变量,或者传给函数,响应式连接会断:
const state = reactive({ count: 0 })
// count 和 state.count 断开连接了
let { count } = state
count++ // 不影响原始 state
// 函数收到的是普通数字,追踪不到变化
callSomeFunction(state.count)
Tip因为有这些限制,官方推荐用
ref()作为声明响应式状态的主要 API。
ref vs reactive 怎么选
| 场景 | 推荐 |
|---|---|
| 原始类型值(string、number、boolean) | ref() |
| 对象(需要保持引用不变) | reactive() |
| 对象(可能整体替换) | ref() |
| 不确定 | ref() |
简单记:默认用 ref(),遇到复杂对象再考虑 reactive()。
本节回顾
ref()包装值成带.value的对象,模板里自动解包reactive()让对象本身响应式,不需要.valuereactive()有类型限制、不能替换整体、解构丢失连接- 推荐
ref()作为首选 API <script setup>让代码更简洁