响应式核心:ref 与 reactive
- 理解 Vue3 响应式的基本原理
- 掌握
ref和reactive的定义、使用与选型 - 熟练使用
<script setup>语法糖组织代码
1. 响应式原理
一句话:数据变化时,页面自动更新。
Vue3 实现三部曲
- 代理(Proxy):把数据对象包一层代理,所有读写都经过它
- 读取记账:模板渲染时读数据,代理记下“谁在用这个数据”(收集依赖)
- 修改广播:数据被改,代理通知所有依赖它的地方重新渲染
2.ref—— 单个值的“快递盒”
为什么需要 ref?
Proxy只能代理对象,不能直接代理基本类型(数字、字符串)。
ref 将基本类型包装成对象:{ value: 实际值 },再对这个对象做代理。
基本用法
import{ref}from'vue'constcount=ref(0)// 定义count.value++// 修改(必须 .value)console.log(count.value)// 读取(必须 .value)模板中自动拆箱
<template><p>{{ count }}</p><!-- 直接写 count,不用 .value --><button@click="count++">+1</button></template>口诀:JS 里
.value,模板里不用。
ref 可以存任何值
constuser=ref({name:'林小满'})// 对象也可以装进 refuser.value.name='小满'// 修改仍需 .value内部原理:ref 存对象时,会用
reactive处理.value里的对象,使其深层响应式。
3.reactive—— 一组数据的“玻璃柜”
适用场景
适合处理对象或数组,所有属性被自动代理,无需.value。
import{reactive}from'vue'constuser=reactive({name:'林小满',age:18})user.age++// 直接操作属性user.name='小满'重要限制
- 不能整体替换:
user = reactive({...})或user = { ... }会丢失响应性(原来的代理被替换掉了) - 解构会丢失响应:
const { name } = user解出的name是普通值,修改后页面不更新 - 只接受对象/数组:不能传入基本类型
正确做法:
- 用
ref存需要整体替换的对象:const user = ref({...}),替换时user.value = newObj - 直接通过
user.xxx修改属性,而不是解构
4.refvsreactive选型指南
| 场景 | 推荐 | 原因 |
|---|---|---|
| 单个值(数字/字符串/布尔) | ref | reactive 不支持基本类型 |
| 一组相关数据,且很少整体替换 | reactive | 少写 .value,语义清晰 |
| 数据可能整体替换(如从接口获取新对象) | ref | reactive 整体替换会失效 |
| 对象/数组,但不确定用哪种 | ref | 官方推荐默认使用 ref,行为更统一 |
选型口诀:单值用 ref,整组用 reactive,拿不准就 ref。
5.<script setup>语法糖
<script setup>是 Vue3 推荐的单文件组件写法,自动暴露顶层变量和函数给模板,无需return。
对比:
<!-- 旧写法:必须在 setup() 中 return --> <script> export default { setup() { const count = ref(0) return { count } // 必须 return } } </script><!-- 新写法:<script setup> 自动暴露 --> <script setup> const count = ref(0) // 顶层变量,模板可直接使用 </script>三大自动:
- 顶层变量 → 模板直接使用
- 顶层函数 → 模板直接绑定事件
- import 引入的组件 → 模板直接作为标签使用(第7课)
6. 实战要点:可编辑个人资料页
数据设计思路
- 单个状态值(如编辑开关
editing、座右铭索引)→ref - 一组关联的资料对象(如
profile、编辑草稿form)→reactive
constprofile=reactive({name:'林小满',title:'前端',city:'杭州',intro:'...',skills:[...]})constform=reactive({name:'',title:'',city:'',intro:''})constediting=ref(false)编辑流程
- 进入编辑:将
profile的值拷贝到form,editing.value = true - 表单输入:使用
:value配合@input实现双向数据绑定<input:value="form.name"@input="e => form.name = e.target.value"/>本质是 Vue 的
v-model(第6课正式学),此处手动演示原理。 - 保存:将
form的值回写到profile,editing.value = false,视图自动更新 - 取消:直接
editing.value = false,草稿丢弃
座右铭轮换(ref 应用)
constmottoes=['代码如诗','写注释','先跑通再优化']constmottoIndex=ref(0)functionnextMotto(){mottoIndex.value=(mottoIndex.value+1)%mottoes.length}7. 常见错误与排查
| 错误写法 | 现象 | 正确写法 |
|---|---|---|
editing = true(忘 .value) | 页面无反应 | editing.value = true |
{{ count.value }}(模板多用 .value) | 显示 undefined 或空白 | {{ count }} |
user = reactive({...})(整体替换 reactive) | 页面不更新 | 用ref存对象,或逐属性修改 |
const { name } = user(解构 reactive) | 改 name 页面不更新 | 直接user.name = ... |
记忆:reactive 是“玻璃柜”,只能动柜子里的东西,不能把柜子整个换掉。
小结速查
| 概念 | 要点 |
|---|---|
| 响应式 | 代理 + 广播 + 自动重渲染 |
ref | 装盒;JS 里.value,模板里自动拆;可存任何类型 |
reactive | 装柜;直接操作属性;不能整体替换;不能解构 |
| 选型 | 单值 → ref;整组 → reactive;不确定 → ref |
<script setup> | 顶层变量/函数自动暴露,无需 return |