Vue3: 如何在 ref() 和 reactive() 中做选择

Vue 3 中响应式的两大核心 API:ref()reactive() 的原理与用法。


一、ref()

1. 用法

  • ref() 用于为基本类型(如字符串、数字、布尔值)或对象/数组创建一个响应式的数据引用。
  • 它返回一个带有 .value 属性的响应式对象。

示例

1
2
3
4
5
6
7
import { ref } from 'vue'

const count = ref(0) // 基本类型
const user = ref({ name: 'Tom' }) // 对象类型

count.value++ // 访问和修改时要用 .value
user.value.name = 'Jerry'

2. 原理

  • ref() 内部通过 Object.defineProperty 或 Proxy 实现,将传入的值包裹在一个对象的 value 属性中。
  • .value 发生变化时,依赖于它的组件会自动重新渲染。

3. 适用场景

  • 适合基本类型数据(如数字、字符串、布尔值)。
  • 也可用于对象/数组,但访问和赋值都要通过 .value

二、reactive()

1. 用法

  • reactive() 用于将一个对象或数组变成响应式对象。
  • 返回的就是原对象的 Proxy 代理,不需要 .value

示例

1
2
3
4
5
6
7
8
9
import { reactive } from 'vue'

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

state.count++ // 直接访问和修改
state.user.name = 'Jerry'

2. 原理

  • reactive() 内部通过 ES6 的 Proxy 拦截对象的 get/set 操作,实现依赖收集和响应式更新。
  • 只有对象和数组才能用 reactive()基本类型不能直接用

3. 适用场景

  • 适合复杂的对象/数组,如组件的 state、表单数据等。
  • 访问和赋值都像普通对象一样,无需 .value

三、ref() 和 reactive() 的区别与联系

特点 ref() reactive()
适用类型 基本类型/对象/数组 对象/数组
访问方式 通过 .value 直接访问属性
内部实现 对象包装 + Proxy/defineProperty Proxy
响应式深度 浅层响应式(对象时递归) 深层响应式
典型场景 单个变量、基本类型 复杂对象、表单、state

例子

1
2
3
4
5
const a = ref(1)
a.value = 2

const b = reactive({ x: 1 })
b.x = 2

ref 对象的自动解包(在模板中)

<template> 里,ref.value 会被自动解包,可以直接用 {{ count }} 而不是 {{ count.value }}


四、进阶:ref 和 reactive 混用

  • reactive 里嵌套 ref,属性不会自动解包,需手动 .value
  • 推荐:对象用 reactive,基本类型用 ref

示例

1
2
3
4
const state = reactive({
count: ref(0)
})
state.count.value++ // 需要 .value

五、总结

  • 基本类型ref()对象/数组reactive()
  • ref 适合单一变量,reactive 适合复杂结构。
  • 访问 ref.valuereactive 直接访问。
  • <template> 中,ref 会自动解包。