人人都会AI编程

核心响应式 API:ref、reactive、toRef、toRefs、unref

更新时间:2026-07-11

组合式 API 中,响应式数据的创建和转换是最基础的操作。掌握这几个核心 API 的区别与适用场景,能让你在编写逻辑时避免一大半的响应式失效问题。

ref

ref 是创建响应式数据的“万能工具”。它接受一个内部值(可以是基本类型或对象),返回一个 ref 对象,通过 .value 属性访问和修改。

import { ref } from 'vue'

const count = ref(0)
const user = ref({ name: 'Alice' })

// 在 script 中必须通过 .value 操作
count.value++
user.value.name = 'Bob'

模板中的自动解包:在 template 中使用 ref 时,Vue 会自动“拆开” ref 对象,你直接写变量名即可,无需 .value

<template>
  <p>{{ count }}</p>   <!-- 自动解包,不需要 count.value -->
</template>

为何需要 .value:Vue 的响应式需要追踪“对值的读写”。基本类型(如数字)在 JavaScript 中是值传递,函数参数无法保持引用,因此必须用对象包裹一层。通过 .value 的 getter/setter,Vue 才能拦截对基础类型数据的修改。

reactive

reactive 用于将对象或数组转换为响应式代理,直接返回一个 Proxy 对象,访问属性不需要 .value

import { reactive } from 'vue'

const state = reactive({
  count: 0,
  user: { name: 'Alice' }
})

// 直接修改属性
state.count++
state.user.name = 'Bob'

核心优势:写法自然,等同于操作普通对象,深层嵌套的属性也会自动被代理。缺点:不能整体替换对象本身(state = something 会丢失响应式),且解构或展开时会丢失响应式。

const { count } = state  // count 现在是普通数字,不再响应式!

选型原则

  • 基本类型值,用 ref
  • 需要整体替换的对象,用 ref
  • 固定结构的对象(如表单数据),不想写大量 .value,用 reactive
  • 从逻辑层返回数据给模板时,也可以 reactive 包裹,配合 toRefs 解构。

toRef

toRef 用于从 reactive 对象上“接出一条”属性,并保持这个属性与源对象的响应式链接。返回的是一个 ref。

const state = reactive({ count: 0, name: 'Vue' })

// countRef 是一个 ref,它和 state.count 保持同步
const countRef = toRef(state, 'count')

countRef.value++   // state.count 也变成 1
state.count++      // countRef.value 也变成 2

何时用它? 当你需要把一个响应式对象的单个属性作为独立响应式数据传递(比如传入一个组合函数,或作为 props 的响应式源),又不想切断它与原对象的关联时。

toRefs

toRefs 将整个 reactive 对象的每个属性都转换为一个 ref,返回一个普通对象,里面每个属性都是 ref。

const state = reactive({ x: 0, y: 0 })

// 解构后依然保持响应式!
const { x, y } = toRefs(state)
// 现在 x 和 y 都是 ref,修改它们会影响 state,反之亦然

最常见场景:解构 reactive
当你在组合式函数内部使用 reactive 管理状态,并需要 return 给外部使用时,toRefs 几乎是标准操作:

function useMouse() {
  const pos = reactive({ x: 0, y: 0 })
  // 外部可以解构使用,且保持响应式
  return { ...toRefs(pos), /* 其他方法 */ }
}

unref

unref 是一个语法糖:如果参数是 ref,返回 .value;否则返回参数本身。常用于处理“可能是 ref,也可能是普通值”的场景。

import { unref } from 'vue'

const maybeRef = someCondition ? ref(10) : 10
const realValue = unref(maybeRef)   // 无论怎样都拿到纯值

实际用处:编写工具函数或自定义 Hook 时,经常需要兼容传入的参数可能是 ref,让你不用到处写 isRef(param) ? param.value : param,代码更干净。

重点小结

  • ref:创建任意类型的响应式数据,.value 读写,模板自动解包。
  • reactive:对象/数组的响应式代理,无需 .value,但解构会失去响应式。
  • toRef:从一个 reactive 对象中“拔出”一个属性为 ref,保持关联。
  • toRefs:将整个 reactive 对象的所有属性转为 ref 集合,用于安全解构。
  • unref:取 ref 的值或返回本身,方便处理“可能是 ref”的参数。

这几个 API 构成了 Vue 3 响应式数据操作的基础,理解它们的职责边界,就能在复杂逻辑中仍然保持清晰的响应式链路。