深入理解ref、reactive【Vue3工程级指南】

这篇文章的目标只有一个:让你在任何场景下,都能毫不犹豫地判断:这个地方该用 ref ,还是 reactive

目录

  • 响应式的本质不是变量
  • [ref 是什么?什么时候该用 ref?](#ref 是什么?什么时候该用 ref?)
    • [ref 的本质](#ref 的本质)
    • [什么时候必须用 ref(重点)](#什么时候必须用 ref(重点))
      • [场景 1:基本类型](#场景 1:基本类型)
      • [场景 2:对象 / 数组会被整体替换](#场景 2:对象 / 数组会被整体替换)
      • [场景 3:对象是"状态",而不是"模型"](#场景 3:对象是“状态”,而不是“模型”)
    • [ref 的优缺点](#ref 的优缺点)
  • [reactive 是什么?什么时候该用 reactive?](#reactive 是什么?什么时候该用 reactive?)
    • [reactive 的本质](#reactive 的本质)
    • [什么时候 reactive 是最优解](#什么时候 reactive 是最优解)
      • [场景 1:表单对象](#场景 1:表单对象)
      • [场景 2:长期存在的业务模型](#场景 2:长期存在的业务模型)
    • [reactive 的优缺点](#reactive 的优缺点)
  • [对象到底用 ref 还是 reactive?](#对象到底用 ref 还是 reactive?)
  • 响应式是怎么"失去"的
    • [reactive 失效的三大原因](#reactive 失效的三大原因)
    • [ref 失效的常见原因](#ref 失效的常见原因)
  • [toRef / toRefs:解决解构问题](#toRef / toRefs:解决解构问题)
    • [toRef 是什么](#toRef 是什么)
    • [toRefs 批量使用](#toRefs 批量使用)
  • 总结

响应式的本质不是变量

在 Vue3 里,响应式的本质不是变量,而是"引用关系"

  • ref :用一个对象包住一个值,通过 .value 访问
  • reactive :用 Proxy 代理一个对象

⚠️:Vue 追踪的不是变量名,而是 ref.value 或 Proxy 内部的属性访问

ref 是什么?什么时候该用 ref?

ref 的本质

typescript 复制代码
const count = ref(0)
  • count 是一个对象
  • 真正的值在 count.value
  • Vue 通过 getter / setter 追踪 .value

在模板里:

typescript 复制代码
{{ count }} // 自动解包

在js/ts中:

typescript 复制代码
count.value++

什么时候必须用 ref(重点)

场景 1:基本类型

typescript 复制代码
const loading = ref(false)
const page = ref(1)
const keyword = ref('')

场景 2:对象 / 数组会被整体替换

typescript 复制代码
const list = ref<Item[]>([])
list.value = res.data

如果用 reactive:

typescript 复制代码
const list = reactive([])
list = res.data // ❌ 直接失效

只要你会写 = 重新赋值,就用 ref!!!

场景 3:对象是"状态",而不是"模型"

什么是状态,什么是模型???

typescript 复制代码
const currentRow = ref<Row | null>(null)
  • 有 / 没有
  • 选中 / 取消
  • 打开 / 关闭

这是状态,不是业务结构

ref 的优缺点

优点:

  • 可以整体替换
  • 可以为 null / undefined
  • 解构安全
  • 状态语义清晰

缺点:

  • JS 中需要 .value
  • 对象层级深时略显啰嗦

reactive 是什么?什么时候该用 reactive?

reactive 的本质

typescript 复制代码
const form = reactive({ name: '', age: 18 })
  • 返回的是一个 Proxy
  • 每个属性访问都会被 Vue 追踪
  • 没有 .value

什么时候 reactive 是最优解

场景 1:表单对象

typescript 复制代码
const form = reactive({
	name: '',
	age: 0,
	role: ''
})

原因:

  • 字段多
  • 高频修改单字段
  • v-model 非常频繁
  • 不需要整体替换

场景 2:长期存在的业务模型

typescript 复制代码
const state = reactive({
	loading: false,
	page: 1,
	pageSize: 10
})

这些数据:

  • 生命周期一致
  • 逻辑上属于一组
  • 不会被整体重置

reactive 的优缺点

优点:

  • 写法自然
  • 表单 / v-model 体验极佳
  • 代码可读性高

缺点:

  • ❌ 不能整体替换
  • ❌ 不能为 null
  • ❌ 解构会丢响应式

对象到底用 ref 还是 reactive?

四个问题法(直接用)

ref reactive
会不会被整体替换 会 -> ref 不会 -> reactive
关心"对象是谁"or"字段怎么变"? 是谁 -> ref 字段 -> reactive
会不会大量 v-model 会 -> reactive
是不是长期业务模型 是 -> reactive

响应式是怎么"失去"的

reactive 失效的三大原因

typescript 复制代码
form = newForm // ❌ 整体替换
const { name } = form // ❌ 解构
JSON.parse(JSON.stringify(form)) // ❌ 深拷贝

正确做法:

typescript 复制代码
Object.assign(form, newForm)

ref 失效的常见原因

typescript 复制代码
const c = count.value // ❌ 断开引用 

因为这里只是把count这个响应式的值给了c而已

toRef / toRefs:解决解构问题

toRef 是什么

typescript 复制代码
const name = toRef(form, 'name')
  • 把 reactive 的某个字段变成 ref
  • 双向同步

toRefs 批量使用

typescript 复制代码
const { name, age } = toRefs(form)

它们的原理都是 把reactive 内的变量都解构成响应式的ref包裹的变量

总结

  • reactive 负责"结构"
  • ref 负责"状态"
相关推荐
晚霞的不甘6 分钟前
揭秘 CANN 内存管理:如何让大模型在小设备上“轻装上阵”?
前端·数据库·经验分享·flutter·3d
小迷糊的学习记录15 分钟前
0.1 + 0.2 不等于 0.3
前端·javascript·面试
空&白37 分钟前
vue暗黑模式
javascript·vue.js
梦帮科技1 小时前
Node.js配置生成器CLI工具开发实战
前端·人工智能·windows·前端框架·node.js·json
VT.馒头1 小时前
【力扣】2695. 包装数组
前端·javascript·算法·leetcode·职场和发展·typescript
css趣多多2 小时前
一个UI内置组件el-scrollbar
前端·javascript·vue.js
-凌凌漆-2 小时前
【vue】pinia中的值使用 v-model绑定出现[object Object]
javascript·vue.js·ecmascript
C澒2 小时前
前端整洁架构(Clean Architecture)实战解析:从理论到 Todo 项目落地
前端·架构·系统架构·前端框架
C澒2 小时前
Remesh 框架详解:基于 CQRS 的前端领域驱动设计方案
前端·架构·前端框架·状态模式
Charlie_lll2 小时前
学习Three.js–雪花
前端·three.js