深入理解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 负责"状态"
相关推荐
广州华水科技4 小时前
北斗形变监测传感器在大坝安全监测中的应用与优势分析
前端
孔令飞4 小时前
如何学习Go
前端
HUIBUR科技4 小时前
AI 中枢,面向企业场景构建的 AI 智能体
前端·数据库·人工智能
怕浪猫5 小时前
给AI配一台电脑,开源版Muse来了,OpenMuse赶紧去二次开发吧
javascript·面试·github
随便写个软件5 小时前
【新版本】EasyExplorer资源管理器 3.12.0——地址栏重要更新
运维·服务器·前端·everything·资源管理器
Jack N5 小时前
【Strapi 系列之二】Collection / Single / Component 怎么选?Strapi 字段大全一篇讲透
前端·javascript·strapi
hiahiahia1235 小时前
Agent Tool 执行失败怎么办
服务器·前端
Java后端的Ai之路5 小时前
09-React组件生命周期
前端·react.js·前端框架
撸串-研究生5 小时前
面向景区的综合服务管理平台设计——以稻城亚丁景区为例【附源码】
java·开发语言·vue.js·前后端分离·稻城亚丁景区
IT_陈寒5 小时前
SpringBoot开发实战:从入门到精通
前端·人工智能·后端