目录
- [Vue3 中 ref 与 reactive:状态与模型的深入理解](#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 仅在变量会被重赋值时使用