Vue3 中的响应式
本文将介绍 Vue3 中两种可以实现响应式变量的方法:ref
和 reactive
。此外,我们还将对 Vue3 中常用的响应式 API 进行简要介绍。
ref
- 通过 ref 创建的变量,会被自动包装成响应式对象。若想访问该变量的值,需要通过
.value
来访问。 - ref 可以包装基本类型的数据,也可以包装对象。对于基本类型,会直接返回一个响应式对象;对于对象,会返回一个包装后的对象。对象内部还是会调用 reactive 进行包装。
- ref 包装的对象是深层响应式的,即对象内部的嵌套对象也是可以被监听更新的。同时,可以通过 shallowRef 创建一个浅层响应式对象。
- ref 对 DOM 的更新是异步的,可以通过
nextTick
来获取更新后的值。对于该方法的调用,可以在异步函数里,也可以传入回调函数。
reactive
- ref 是将对象包装成响应式对象,而 reactive 是使对象本身具有响应式。
- 响应式对象的本质是一个 JS 代理,通过 reactive 生成的对象和原对象不是同一个对象,但通过 reactive 生成的对象再次通过 reactives 生成的对象是同一个对象。通俗的说,对于一个普通对象,reactive 会返回一个 proxy,但是对于 reactive 变量,再次调用 reactive 会返回它本身。
- reactive 包装的对象是深层响应式的,即对象内部的嵌套对象也是可以被监听更新的。同时,可以通过 shallowReactive 创建一个浅层响应式对象。
- reactive 的局限性
- 有限类型:reactive 只能监听对象,不能监听基本类型数据。
- 不能替换整个对象:reactive 如果替换掉整个对象,之前的响应式跟踪会被丢弃。
- 对解构操作不友好:解构操作会丢失响应式跟踪。也就是说,解构以后的变量是一个普通的变量,不具有响应性。
额外的 ref 解包细节
- 作为 reactive 对象的属性的时候,ref 对象会自动解包,不需要通过
.value
来访问。 - 作为 shallowReactive 对象的属性的时候,ref 对象不会自动解包,需要通过
.value
来访问。 - 在模板渲染上下文里,只有顶级的 ref 对象会被解包。非顶级 ref 对象的模板渲染需要通过手动解包或者解构进行访问。其中,特殊情况是如果渲染的最终结果就是 ref 对象本身,可以实现解包的效果。
响应式常用 API
响应式常用 API 可以分为以下四类:
- ref 相关:toRef、toRefs、unref
- 只读代理:readonly
- 判断相关:isRef、isReactive、isReadonly、isProxy
- 3.3 新增 API:toValue
ref 相关
- toRef:将一个响应式对象的属性转换为 ref 对象,返回一个 ref 对象。
- toRefs:将一个响应式对象转换为普通对象,该对象的每个属性都是 ref 对象。
- unref:如果参数是 ref,返回内部值;如果不是 ref,返回参数本身。
只读代理
- 接受一个对象,无论是否是响应式对象,返回一个该对象的只读代理。
- 某些场景下,希望数据只能读取不能修改——config 配置等。
判断相关
- isRef:判断一个对象是否是 ref 对象。
- isReactive:判断一个对象是否是 reactive 对象。
- isReadonly:判断一个对象是否是 readonly 对象。
- isProxy:判断一个对象是否是由 reactive、shallowReactive、readonly、shallowReadonly 创建的代理对象。
3.3 新增 API
- toValue:将一个 ref 对象转换为普通对象,返回 ref 对象的内部值。
- 比 unref 更灵活,支持传入 getter 函数,并且返回函数的执行结果。