首页 / Vue3 入门教程 / 响应式基础(上)

Vue3 入门教程

响应式基础(上)

本教程共 40 篇 · 第 4 篇 · 更新于 2026-07-29 · 约 8 分钟阅读

VueVue3 入门教程refreactive响应式Composition API

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() 让对象本身响应式,不需要 .value
  • reactive() 有类型限制、不能替换整体、解构丢失连接
  • 推荐 ref() 作为首选 API
  • <script setup> 让代码更简洁