从入门到精通:Vue3 ref vs reactive 最佳实践与底层原理

在 Vue 3 中,ref 和 reactive 是 Composition API 提供的两个核心响应式 API,用于创建响应式状态。它们都基于 JavaScript 的 Proxy(reactive)和 getter/setter(ref 的内部机制)来实现响应式追踪,但在使用场景和行为上有一些关键区别。


1. ref

用途

  • 用于定义基本数据类型 (如 string, number, boolean)的响应式数据。
  • 也可以用于定义对象或数组 ,此时内部会自动调用 reactive。
  • 在模板中使用时,无需 .value,Vue 会自动解包。
  • 在 JavaScript 中访问或修改时,必须通过 .value。

示例

csharp 复制代码
import { ref } from 'vue'

const count = ref(0)
console.log(count.value) // 0

count.value++
xml 复制代码
<template>
  <p>{{ count }}</p> <!-- 自动解包,无需 .value -->
  <button @click="count++">增加</button>
</template>

特点

  • 适用于任何类型。
  • 对于对象/数组,ref 内部会调用 reactive。
  • 可以通过 ref() 创建对对象的响应式引用,保留其引用身份(identity)。

2. reactive

用途

  • 专门用于定义对象或数组类型的响应式数据。
  • 不能用于基本数据类型 (如 number, string)。
  • 返回的是一个代理对象(Proxy),直接操作其属性即可,不需要 .value。

示例

php 复制代码
import { reactive } from 'vue'

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

state.count++
state.user.name = 'Bob'
xml 复制代码
<template>
  <p>{{ state.count }}</p>
  <p>{{ state.user.name }}</p>
</template>

特点

  • 只能用于对象/数组。

  • 返回的是原始对象的代理,无法替换整个对象(否则失去响应性)。

    ini 复制代码
    // ❌ 错误做法:直接赋值新对象会丢失响应性
    state = { count: 1 } 
    
    // ✅ 正确做法:修改属性
    state.count = 1

对比总结

特性 ref reactive
支持类型 任意类型(基本类型 + 对象/数组) 仅对象或数组
访问方式(JS 中) 需 .value 直接访问属性
模板中使用 自动解包,无需 .value 直接访问
替换整个对象 可以(重新赋值 .value) 不可以(会丢失响应性)
内部实现 基本类型用 getter/setter;对象用 reactive 基于 Proxy
适用场景 简单值、需要替换整个对象的情况 复杂对象状态管理

最佳实践建议

  • 优先使用 ref :尤其在 TypeScript 项目中,ref 的类型推断更直观,且统一使用 .value 有助于代码一致性。
  • 当你有一个复杂的对象状态,并且不需要替换整个对象时,可以使用 reactive。
  • 避免混用导致困惑。例如,不要在一个 reactive 对象中嵌套 ref 除非必要(虽然 Vue 会自动解包,但可能影响可读性)。

补充:toRefs 和 toRef

当你从 reactive 对象中解构属性时,会丢失响应性。此时可使用 toRefs 或 toRef:

javascript 复制代码
import { reactive, toRefs } from 'vue'

const state = reactive({ count: 0 })
const { count } = toRefs(state) // count 是一个 ref

count.value++ // 仍然响应式
相关推荐
开开心心就好34 分钟前
竖式除法出题工具,整除余数混合模式
运维·服务器·前端·javascript·ocr·perl·1024程序员节
起个名字费劲死了42 分钟前
Halcon学习一:骰子识别
前端·python·学习
大江东去浪淘尽千古风流人物1 小时前
【HexVIO】DSP卸载双目惯性VIO:Hexagon向量化前端与单帧融合调度深度解析
前端·状态模式·slam·dsp·vio·hexagon·移动端加速
其实防守也摸鱼1 小时前
Chrome 扩展安全攻防实录:从攻击面到防御实践
开发语言·前端·网络·chrome·安全·web安全·php
web打印社区1 小时前
Lodop排障总纲-常见报错一张表
开发语言·前端·javascript·chrome·websocket
李剑一1 小时前
为什么几乎所有的知名开源项目都是外国人写的?
前端·ai编程·deepseek
小郎君6581 小时前
(一)为什么表单需要第三种状态:disabled、readonly 与纯文本展示
前端·vue.js
计算机魔术师1 小时前
1.4万亿没人接,OpenAI自己砍了1500亿
前端
溪语流沙2 小时前
【每天一个CSS | Day41】开关三连:一套状态机,三种视觉翻译
前端·css·html5·每日一练·按钮
变与不变8062 小时前
css定位布局精讲
前端·css