reactive
2023年05月03日
一、认识
reactive
返回一个对象的响应式代理。通过 reactive
的响应式转换是深层的: 它会影响到所有嵌套的属性。一个响应式对象也将深层地解包任何 ref
属性,同时保持响应性。值得注意的是,当访问到某个响应式数组或 Map
这样的原生集合类型中的 ref
元素时,不会执行 ref
的解包。若要避免深层响应式转换,只想保留对这个对象顶层次访问的响应性,请使用 shallowReactive()
作替代。返回的对象以及其中嵌套的对象都会通过 ES Proxy
包裹,因此不等于源对象,建议只使用响应式代理,避免使用原始对象。
二、语法
2.1 创建响应式对象
<template>
<div>
{{ obj.a }}
<button @click="changeObj">按钮</button>
</div>
</template>
<script setup lang="ts">
import { reactive } from 'vue'
const obj = reactive({
a: '哈哈',
b: '嘻嘻'
})
const changeObj = () => {
obj.a += '修改'
}
</script>
2.2 创建响应式数组
<template>
<div>
{{ obj[0] }}
<button @click="changeObj">按钮</button>
</div>
</template>
<script setup lang="ts">
import { reactive } from 'vue'
const obj = reactive(['哈哈', '嘻嘻'])
const changeObj = () => {
obj[0] += '修改'
}
</script>
2.3 创建响应式Map
reactive
创建带有 ref
属性的 Map
时, 当访问到某个响应式数组的 ref
元素时, 不会执行 ref
的解包。
<template>
<div>
{{ obj.get('a') }}
<button @click="changeA">按钮 A</button>
<button @click="changeObj">按钮 Obj</button>
</div>
</template>
<script setup lang="ts">
import { ref, reactive, type Ref } from 'vue'
type ObjType = Map<string, Ref<number>>
const a = ref(0)
const obj:ObjType = reactive(new Map([['a', a]]))
const changeA = () => {
a.value += 1
}
console.log(obj)
const changeObj = () => {
changeA();
obj.set('a', a)
console.log(a.value)
console.log(obj.get('a')?.value)
}
</script>
2.4 创建带有 ref 的响应式对象
reactive
创建带有 ref
属性的对象时, 访问 ref
属性会自动解包。此后,无论是更新 ref
数据还是更新 reactive
中的 ref
属性值, 都会同步更新。
<template>
<div>
{{ obj.a }}
<button @click="changeA">按钮 A</button>
<button @click="changeObj">按钮 Obj</button>
</div>
</template>
<script setup lang="ts">
import { ref, reactive } from 'vue'
const a = ref(0)
const obj = reactive({
a
})
const changeA = () => {
a.value += 1
console.log(a.value)
console.log(obj.a)
}
const changeObj = () => {
obj.a += 1
console.log(a.value)
console.log(obj.a)
}
</script>
2.5 创建带有 ref 的响应数组
reactive
创建带有 ref
属性的数组时, 当访问到某个响应式数组的 ref
元素时, 不会执行 ref
的解包。此后,无论是更新 ref
数据还是更新 reactive
中的 ref
属性值, 都会同步更新。
<template>
<div>
{{ obj[0] }}
<button @click="changeA">按钮 A</button>
<button @click="changeObj">按钮 Obj</button>
</div>
</template>
<script setup lang="ts">
import { ref, reactive, type Ref } from 'vue'
type ObjType = [Ref<number>, number]
const a = ref(0)
const obj: ObjType = reactive([a, 1])
const changeA = () => {
a.value += 1
console.log(a.value)
console.log(obj[0].value)
}
const changeObj = () => {
obj[0].value += 1
console.log(a.value)
console.log(obj[0].value)
}
</script>
三、问题
3.1 reactive 有什么局限性?
reactive
本质上是通过 Proxy
代理对象, 因此 reactive
的局限性其实就是 Proxy
的局限性。Proxy
的局限性如下:
-
Proxy
只可以代理引用类型数据 -
Proxy
代理对象解构之后的属性将不会触发handler