vue3的响应式的理解,与普通对象的区别(一)
主要是在使用过程中经常出现非预期情况,基本都是对其响应式原理不是理解的很透彻。
先看下网络上查找到一些资料都不是很直观,具体使用时还是懵懵懂懂。
什么是响应式?
当依赖数据发生改变时,与之关联的数据或计算结果能够自动更新就是响应式。
我现在的理解是,响应式对象 = 代理 + 触发器。
vue3 中响应式对象主要分为ref、reactive、computed、props四种类型。
特性 | ref | reactive | computed | props |
---|---|---|---|---|
用途 | 包装基本类型(如 number 、string 等) | 包装对象或数组 | 基于响应式数据计算得出新值 | 父组件向子组件传递数据 |
返回值类型 | 返回一个 ref 对象(包含 .value 属性) | 返回一个响应式代理对象 | 返回一个只读的 ref 对象 | 普通对象(经过 Vue 代理,具有响应性) |
是否可写 | 可写(通过 .value 修改) | 可写(直接修改属性) | 默认只读(可通过 get /set 实现可写) | 只读(不能直接修改) |
是否需要 .value | 需要(在 JS 中) | 不需要 | 需要(在 JS 中) | 不需要 |
模板中使用 | 自动解包,不需要 .value | 直接访问属性 | 自动解包,不需要 .value | 直接访问属性 |
响应性来源 | 通过 .value 触发响应式更新 | 直接通过属性访问触发响应式更新 | 基于依赖的响应式数据自动更新 | 继承父组件传递的响应式数据 |
适用场景 | 基本类型数据、单个值 | 对象或数组 | 需要动态计算的属性 | 父组件向子组件传递数据 |
示例 | const count = ref(0); | const state = reactive({ count: 0 }); | const double = computed(() => count.value * 2); | props: { count: Number } |
一个对象有且仅有2个功能,1.读取;2修改;所以只要把这2个功能使用情况分析清楚就明白到底什么时候响应式对象了。
1.读取功能
响应式对象读取的是一个代理对象,普通对象读取的就是实际的真实对象。如果只是取值的话,通过代理读取对象和直接读取对象,其实是一样的效果。
这里主要注意:
1.1 读取数据时是否需要.value。具体参照上面表格对照。
1.2 读取返回值对象类型。是代理对象还是真实对象。具体参照上面表格对照。
1.3 依赖收集(Track)
在访问响应式数据时,Vue 会通过 依赖收集 来记录哪些地方(如组件、计算属性、侦听器等)依赖了这些数据。
-
触发时机:当访问响应式数据的属性时。
-
作用:记录当前正在运行的副作用(如
effect
、computed
、watch
等)。 -
示例:
const state = reactive({ count: 0 }); effect(() => { console.log(state.count); // 访问 state.count,触发依赖收集 });
2.修改功能
此时,代理对象的作用就体现了。修改数据时,如果是直接通过真实对象引用修改数据,则不会触发相关触发器,执行一系列任务。但是代理对象就可以。vue3的代理对象中有绑定一些触发器函数,通过代理对象修改数据时,会调用相关触发器,执行一些任务,如渲染DOM、触发监听器钩子函数等。
所以,要理解响应式对象的修改功能,就是要了解修改后,vue3实现了哪些触发器(钩子函数)。
2.1. 组件渲染更新
当响应式数据变化时,Vue 会触发组件的重新渲染。最常见的就是v-model绑定。
-
触发时机:当组件依赖的响应式数据变化时。
-
作用:更新组件的视图。
-
示例:
<template> <div>{{ count }}</div> </template> <script> import { ref } from 'vue'; export default { setup() { const count = ref(0); return { count }; } }; </script>
2.2. 计算属性更新
计算属性是基于响应式数据动态计算得出的值。当依赖的响应式数据变化时,计算属性会重新计算。
-
触发时机:当计算属性依赖的响应式数据变化时。
-
作用:重新计算计算属性的值。
-
示例:
const doubleCount = computed(() => count.value * 2); count.value++; // 触发 doubleCount 重新计算
2.3. 侦听器(Watch)触发
侦听器用于监听响应式数据的变化,并在变化时执行回调函数。
-
触发时机:当侦听的响应式数据变化时。
-
作用:执行回调函数。
-
示例:
watch(count, (newValue, oldValue) => { console.log('Count changed:', newValue); }); count.value++; // 触发 watch 回调
2.4. 生命周期钩子
当响应式数据变化导致组件重新渲染时,Vue 会触发相关的生命周期钩子。
-
触发时机:组件更新时。
-
作用:执行生命周期钩子逻辑。
-
示例:
onUpdated(() => { console.log('组件已更新'); });
当响应式数据变化时,Vue 3 会触发以下机制:
触发器 | 触发时机 | 作用 |
---|---|---|
组件渲染更新 | 组件依赖的响应式数据变化时 | 重新渲染组件 |
计算属性更新 | 计算属性依赖的响应式数据变化时 | 重新计算计算属性的值 |
侦听器(Watch)触发 | 侦听的响应式数据变化时 | 执行侦听器回调函数 |
生命周期钩子 | 组件更新时 | 执行生命周期钩子逻辑 |
总结
使用vue3的响应式对象时,弄清楚对象类型,那种响应式类型(即代理类型),对应有哪些触发器。