4.4 数据绑定与响应式原理


4.4 数据绑定与响应式原理

本节摘要:Vue 的响应式系统靠"数据被读取时记录依赖、数据变化时通知依赖"来工作。ref 包装基础值,reactive 包装对象,依赖追踪让"改数据界面自动变"落地。理解这套原理,你才能摸到头哪些写法会失效、哪些写法高效。

本节阅读目标
阅读完本节,你应当能够:

  1. 区分 ref 与 reactive 的适用对象与使用边界。
  2. 复述依赖追踪"读取记录、变化通知"的基本过程。
  3. 识别会让响应式失效的写法并说明修复方向。

一、为什么"改数据界面跟着变"

这是第 2.3 节思想的 Vue 实现。Vue 把数据包成响应式对象:当你读取它,它记下"谁在依赖我";当你改它,它掏出依赖表,通知那些依赖它的组件重新计算。于是 template 里引用过该数据的文本、指令,一起自动更新。

二、ref 与 reactive 的分工

  • ref:包装单个基础值(数字、字符串、布尔),脚本里用 .value 访问,模板里自动解包。
  • reactive:包装对象/数组,直接访问,无需 .value。
<script setup> import { ref, reactive } from 'vue'; const count = ref(0); const user = reactive({ name: '阿明', age: 28 }); </script> <template> <p>{{ count }} · {{ user.name }}</p> </template>

挑选要领:会整体替换的值用 ref;需要嵌套结构的对象用 reactive。两者都只在你"遵守规则访问"时才跟踪得到。

三、依赖追踪的工作方式

三个动作一条链:读取就登记、变化就通知、组件就重渲。把它画成流程比背文字直观得多。

图:Vue 响应式依赖追踪闭环

图:Vue 响应式依赖追踪闭环

四、失效快照:什么写法不灵

摸清响应式的"边界",效率和安全一起提升。

失效场景 原因 修法
直接给普通变量赋值不更新 没被包成响应式 用 ref / reactive
用下标新增对象属性不追 新增键未登记依赖 用 reactive 提前声明或整体替换
在模板外的普通函数改 ref 忘 .value 访问不当 正确 .value

一段"踩中又要修好"的代码把失效看个明白。下面这个搜索框,如果直接写:

let keyword = '';

然后希望在模板里 {{ keyword }} 跟着输入变,永远做不到——因为它根本没被包成响应式。正确做法是:

import { ref } from 'vue'; const keyword = ref('');

再看"新增键"那个坑:对 reactive 对象从来没出现过的属性,在运行期用 obj.newField = x 塞进去,Vue 是跟踪不到它的(因为新增键时并没有登记依赖)。稳妥办法是:一开始就在对象里占好位,或者整体替换。理解了这两处,就能明白排查方向永远先问一句"我走的是不是响应式通道"。

五、工程取舍

对大多数界面,ref / reactive 就够。响应式的价值是"少写手动同步",但要保的是"按规则用"。后续计算属性、侦听器都是站在这个响应式基座上做的二次抽象(4.5 节)。

两条用得到底铁的响应式实战结论

把本节的机制收成两句不踩坑的经验,够日常支撑很久。第一句:ref 和 reactive 能互转、也能混用,但别在对象里嵌套 ref 之后又期待到处解包reactive({ user: ref('阿明') }) 里那个 ref 在访问时会不会自动解包、赋值时要不要 .value,规则细碎且容易忘。更省心的选择是"浅层都用 ref,需要深结构再整体换成 reactive"——保持类型一致,读取时的心智负担最小。

第二句:当你发现"改成值、界面却不动",先别怀疑框架,先检查自己走的通道。凡是普通变量直接改的直接换 ref/reactive;凡是在异步回调里改响应式数据、却忘了它其实不是响应式的,也要回头包一层。绝大多数"不响应"不是机制坏了,而是你在响应式通道之外改了数据。记住这两条,比背下十条 API 更能守住实际项目的日常安全。

六、把"整棵树都是响应式"真正派上用场

前面讲的是单个值的追踪,实际项目里还要面对一批对象的列表。Vue 的响应式并不会因为你放进一个数组就停手——把数组包进 reactive,列表项的新增、删除、更新同样会被追踪。体会这点,你的"列表数据一变、列表界面自动增删"就不再靠手动重建,而是天然生效:

<script setup> import { reactive } from 'vue'; const todos = reactive([ { id: 1, text: '起床' }, { id: 2, text: '写代码' }, ]); function addTodo(text) { todos.push({ id: Date.now(), text }); } </script> <template> <ul><li v-for="t in todos" :key="t.id">{{ t.text }}</li></ul> </template>

push 一次,界面列表就多一行,不用你手动操作 DOM 再插一个节点。这正是"数据驱动"在 Vue 复含量级上的兑现:维护数据,界面自会跟。要注意的是这里的更新仍要遵守前面"尽量整体替换或多用不可变手法"的偏好——频繁靠 push/splice 就地改,虽然响应式能感知,排查和回退反而麻烦。数据与界面同声共气,是响应式最令人畅快的时刻,也是"少写手动同步"这句目标的完整落地。

本节要点回顾

  • 原理刻度:读取登记、变化通知、依赖组件重渲。
  • ref vs reactive:基础值用 ref(.value),对象/数组用 reactive。
  • 三个失效点:没包、新增键、访问方式不当。
  • 语义优势:精细粒度,改一处只动该动的视图。

响应式让"数据驱动"自动运行。下一节看两个站在它上面的高级工具——计算属性与侦听器,一个管派生值缓存,一个管副作用追变。


作者与出处
原作者: 灏天文库
来源:灏天文库
整理: 灏天文库整理
由灏天文库平台收录,内容或由平台用户上传,仅供学习交流
发布者: 作者: 灏天文库 转发
评论区 (0)
U