跳到主要内容

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 的局限性如下:

  1. Proxy 只可以代理引用类型数据

  2. Proxy 代理对象解构之后的属性将不会触发 handler