响应式核心:ref 与 reactive

响应式核心:ref 与 reactive

响应式核心:ref 与 reactive

  • 理解 Vue3 响应式的基本原理
  • 掌握refreactive的定义、使用与选型
  • 熟练使用<script setup>语法糖组织代码

1. 响应式原理

一句话:数据变化时,页面自动更新。

Vue3 实现三部曲

  1. 代理(Proxy):把数据对象包一层代理,所有读写都经过它
  2. 读取记账:模板渲染时读数据,代理记下“谁在用这个数据”(收集依赖)
  3. 修改广播:数据被改,代理通知所有依赖它的地方重新渲染

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选型指南

场景推荐原因
单个值(数字/字符串/布尔)refreactive 不支持基本类型
一组相关数据,且很少整体替换reactive少写 .value,语义清晰
数据可能整体替换(如从接口获取新对象)refreactive 整体替换会失效
对象/数组,但不确定用哪种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>

三大自动

  1. 顶层变量 → 模板直接使用
  2. 顶层函数 → 模板直接绑定事件
  3. import 引入的组件 → 模板直接作为标签使用(第7课)

6. 实战要点:可编辑个人资料页

数据设计思路

  • 单个状态值(如编辑开关editing、座右铭索引)→ref
  • 一组关联的资料对象(如profile、编辑草稿form)→reactive
constprofile=reactive({name:'林小满',title:'前端',city:'杭州',intro:'...',skills:[...]})constform=reactive({name:'',title:'',city:'',intro:''})constediting=ref(false)

编辑流程

  1. 进入编辑:将profile的值拷贝到formediting.value = true
  2. 表单输入:使用:value配合@input实现双向数据绑定
    <input:value="form.name"@input="e => form.name = e.target.value"/>

    本质是 Vue 的v-model(第6课正式学),此处手动演示原理。

  3. 保存:将form的值回写到profileediting.value = false,视图自动更新
  4. 取消:直接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