Vue3 响应式数据
一、什么是响应式数据?
在 Vue 中,所谓的 “响应式数据”,是指数据具有响应性,数据层(模型)的改变会自动触发数据表示层(视图)的改变。
二、选项式 API 中的响应式数据
在 选项式 API 中,数据的响应化对程序员是 透明 的。只需要在 data 选项中填入相应的数据,Vue 会自行做响应化处理。
三、组合式 API 中的响应式数据
在组合式 API 中,数据的响应式处理需要由程序员手动处理。
下面将详细说明:
四、reactive
1. reactive()
作用:根据一个对象生成 reactive 对象,它是响应式的代理对象
只能处理引用类型
“深层处理”,会影响所有嵌套属性
原对象与 reactive 对象是相互关联的
如果修改 reactive 对象,则原对象会同步更新;
如果修改原对象,reactive 对象也会同步更新。
因为 reactive 对象实质上是原对象的代理,两者指向相同的内存空间。
需要注意的是:
如果直接修改原对象,虽然数据都会更新,但 reactive 对象和 Vue 都无法察觉到数据的更新,因此应该通过 reactive 对象进行数据的修改。
1 |
|
2. shallowReactive()
与 reactive()
的区别在于:不会进行 “深层处理”。
3. isReactive()
检查对象是否是 reactive 对象。
4. 获取 reactive 的属性
如果希望获取 reactive 对象的属性的值,应该通过 reactive名.属性名
获取。
如果希望获取 reactive 对象的属性且不丢失响应性,
- 不能够直接获取,否则获取的是值
- 不能够简单地使用解构语法
let { 属性名 } = reactive名
,否则获取的是值 - 不能够简单地
ref(reactive名.属性名)
,否则只是根据值生成了 ref,不会与原先的属性相关联
正确的做法如下:
通过
toRefs()
获取一个 “普通” 对象,该对象中包含原对象中每个属性对应的 ref 对象,每个 ref 对象都会与对应属性 “响应式连接”1
let propertysRefObj = toRefs(reactive名)
通过
toRef()
获取指定属性对应的 ref 对象,ref 对象会和原属性 “响应式连接”1
let propertyRef = toRef(reactive名, '属性名')
五、ref
1. ref()
作用:根据值生成一个 ref 对象,它是响应式的
ref 对象包含且只包含一个名为 value 的属性,该属性即是目标值。可以将 ref 对象理解为对目标值的引用,并且这个引用是响应式的,因此可以将 ref 称为 响应式引用、响应式 ref
能够处理基本类型,能够处理引用类型
当 ref 处理引用类型时,并不会直接将引用类型作为 value,而是在内部根据引用类型生成 reactive 对象,将 reactive 对象作为 value
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18<script>
import {reactive, ref} from "vue";
export default {
name: "RefAndReactive",
setup() {
let person = {
name: 'Tom',
age: 11
}
let RefPerson = ref(person)
console.log(RefPerson)
console.log(RefPerson.value)
let ReactivePerson = reactive(person)
console.log(ReactivePerson)
}
}
</script>值的访问:
- 如果要访问值,应该通过
ref名.value
访问 - 如果要在选项式 API 和模板中访问值,无需也不应添加 .value,会自动添加
- 如果 ref 对象被作为 reactive 对象的属性,无需也不应添加 .value
- 如果要访问值,应该通过
如果值是基本类型,值与 ref 对象之间是没有任何关联;
如果值是引用类型,值与 ref 对象之间是相互关联的
因为引用类型的值会被转为 reactive 对象
需要注意的是:
同样不应直接修改原对象,以免修改无法被监听。
1 |
|
3. toRef()
传入一个响应式对象和属性名,获取指定属性对应的 ref 对象,ref 对象会和原属性 “响应式连接”。
即使属性不存在,toRef()
也会返回一个可用的 ref 对象。
4. toRefs()
传入一个响应式对象,返回一个 “普通” 对象,该对象中包含原对象中每个属性对应的 ref 对象,每个 ref 对象都会与对应属性 “响应式连接”。
5. isRef()
检查对象是否是 ref 对象。
2. unref()
如果传入 ref 对象,返回原值;否则,直接返回传入值。
本质上是一个语法糖,如下:
1 |
|
6. customRef()
创建自定义的 ref 对象,略。
7. shallowRef()
与 ref()
的区别在于:如果传入引用类型,将不会对其做 reactive 处理。
8. triggerRef()
配合 shallowRef()
使用,用于手动更新值。
因为如果不做 reactive 处理,ref 对象将无法监听到引用类型数据的改变(除非改变指针)。
9. 响应式 ref 和模板 ref
由于该问题和组合式 API 关系更加密切,因此放置在组合式 API 的部分中,具体请看:
Vue3 组合式API - 响应式 ref 和 模板 ref
五、其它 API
1. isProxy
检查对象是否由 reactive 或 readonly 创建。
2. readonly
(1) readonly()
接收一个对象(可以是普通对象、reactive 对象、ref 对象),返回 readonly 对象,它是响应式的、只读的代理对象
需要注意的是:
- “深层处理”,只读代理对象的任何嵌套属性都只读
- 原对象不是只读的
(2) shallowReadonly()
与 readonly()
的区别在于:不会进行 “深层处理”。
(3) isReadonly()
检查对象是否是 readonly 对象。
3. Raw
(1) toRaw()
根据 reactive 对象或 readonly 对象,获取它们对象的原始对象。
有以下两个作用:
- 为了使用时去除代理带来的额外开销
- 用于临时修改数据,且不希望被监听
(2) markRaw()
标记一个对象,使其永远无法转变为代理对象。