【Vue3】 中 ref 与 reactive:状态与模型的深入理解

目录

Vue3 中 ref 与 reactive:状态与模型的深入理解

一、概念区分:状态 vs 模型

在 Vue3 里,理解 状态(State) 和 模型(Model) 的区别,是选用 ref 或 reactive 的核心。

状态(State)

  • 描述"当前的情况",组件或业务逻辑随时间变化的值
  • 生命周期短,通常只在当前页面或组件内存在
  • 用途:驱动界面渲染,表示当前状态

示例(ToB 项目中常见):

ts 复制代码
const loading = ref(false)                // 是否加载中
const currentRow = ref<Row | null>(null) // 当前选中行
const isModalOpen = ref(false)           // 模态框是否打开

特点:

  • 可为空或可替换
  • 整体赋值频繁
  • 对象通常较简单,字段不多

模型(Model / 业务模型)

  • 描述业务对象或数据结构
  • 生命周期相对长,从接口获取到组件销毁
  • 内部字段会频繁修改,但整体对象通常不会被替换

示例(表单对象):

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

特点:

  • 字段多、层级可能复杂
  • 内部字段修改频繁
  • 用于表单绑定、业务数据处理

二、ref vs reactive 使用原则

场景 适合类型 使用原因 优缺点
状态 选中项、loading、modal开关、timer 关注"变量是谁",可能整体替换 ✅ 可空、可替换、生命周期短 ❌ 访问深层字段需要 .value
模型 表单对象、业务实体、配置对象 关注内部字段修改,不会整体替换 ✅ 模板 v-model 友好、字段可直接访问 ❌ 整体替换不行、解构易失效

口诀:

关心整个变量是谁 → 状态 → ref
关心内部字段 → 模型 → reactive

三、典型使用示例

状态(ref)

ts 复制代码
const loading = ref(false)
const currentRow = ref<Row | null>(null)
const isModalOpen = ref(false)

const selectRow = (row: Row) => {
  currentRow.value = row
}
const closeModal = () => {
  currentRow.value = null
  isModalOpen.value = false
}

模型(reactive)

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

// 修改字段
form.name = 'ssy'
form.age = 18
form.enable = false

// 初始化 / 填充表单
Object.assign(form, res.data)

四、响应式失效场景

reactive 失效

  • 整体替换:
ts 复制代码
form = { name: 'new' } // ❌
  • 解构:
ts 复制代码
const { name } = form // ❌
  • 深拷贝 / JSON 化:
ts 复制代码
const copy = JSON.parse(JSON.stringify(form)) // ❌

ref 失效

  • 忘记 .value:
ts 复制代码
count++ // ❌
  • 解构对象字段:
ts 复制代码
const { name } = formRef.value // ❌

解决方法 :使用 toRef 或 toRefs

五、toRef / toRefs 简单说明

  • toRef :将 reactive 对象的某个属性单独变成 ref
  • toRefs :批量生成 ref
ts 复制代码
const form = reactive({ name: '', age: 18 })
const name = toRef(form, 'name')
const { name, age } = toRefs(form)

六、const vs let

  • 默认 const,因为 ref / reactive 内部的值是可变的,不需要重新赋值变量名

  • 使用 let 的场景:

    • 变量名会被重新赋值(timer, editorInstance, 流程变量)
    • 循环累计 / 分支赋值
ts 复制代码
let timer: number | null = null
timer = setTimeout(...)

七、企业级标准写法

ts 复制代码
// 状态
const loading = ref(false)
const list = ref<Item[]>([])
const currentRow = ref<Row | null>(null)

// 表单 / 模型
const form = reactive({
  name: '',
  age: 0,
  role: ''
})

八、总结

  • 状态 → ref:可空、可替换、短生命周期、关心"是谁"
  • 模型 → reactive:字段多、长期存在、关心字段变化
  • toRef / toRefs:解构 reactive 保持响应
  • const 优先,let 仅在变量会被重赋值时使用
相关推荐
Lucky_Turtle几秒前
【HTML】前端页面禁止缩放
前端·html
孟陬5 分钟前
JavaScript 反引号(` backtick)和双引号的不完全等价 ≠ 场景
javascript·node.js·bun
恋猫de小郭5 分钟前
Genkit Dart 1.0 发布,Flutter 原生的 AI Agent 终于完整了
android·前端·flutter
专业程序开发源10 分钟前
django便利店外卖后台管理系统19650-计算机课程设计、毕业设计
java·vue.js·spring boot·后端·python·django·课程设计
思码梁田13 分钟前
CSS transform 转换详解:translate、rotate、scale、skew 与 3D 变换一次讲清
前端·css·transform·skew·scale·translate·rotate
第10086个小白18 分钟前
flutter桌面端打包方式(Inno Setup Compiler)版本
前端·flutter
派小心.31 分钟前
多端数据分析平台的漏斗可以跨端搭建吗?5 步搭出跨端转化漏斗
大数据·运维·服务器·前端·数据分析
IT_陈寒42 分钟前
为什么我的React组件一直在意外重渲染?
前端·人工智能·后端
Su米苏1 小时前
基于 Token 预算的上下文压缩控制器(Context Compaction Controller)
前端·数据库·人工智能
骇客野人1 小时前
Java 开发组件大全覆盖后端主流技术栈(基础、Web、ORM、中间件、微服务、安全、工具、测试、运维、信创适配常用组件)
java·前端·中间件