闽公网安备 35020302035485号
| reactive | ref |
|---|---|
| ❌ 只支持对象和数组(引用数据类型) | ✅ 支持基本数据类型 + 引用数据类型 |
| ✅ 在 <script> 和 <template> 中无差别使用 | ❌ 在 <script> 和 <template> 使用方式不同(在 <script> 中要使用 .value) |
| ❌ 重新分配一个新对象会丢失响应性 | ✅ 重新分配一个新对象不会失去响应 |
| 能直接访问属性 | 需要使用 .value 访问属性 |
| ❌ 将对象传入函数时,失去响应 | ✅ 传入函数时,不会失去响应 |
| ❌ 解构时会丢失响应性,需使用 toRefs | ❌ 解构对象时会丢失响应性,需使用 toRefs |
reactive 用于将对象转换为响应式数据,可以直接访问和修改属性,适用于复杂的嵌套对象和数组。
let obj = reactive({
name: '小明',
age: 18
})
ref 既能声明基本数据类型,也能声明对象和数组// 对象
const state = ref({})
// 数组
const state2 = ref([])
使用 ref,你可以灵活地声明基本数据类型、对象或数组,而不受像 reactive 那样只能处理引用数据类型的限制。这为开发提供了更大的灵活性,尤其是在处理不同类型的数据时。let state = reactive({ count: 0 })
// 这个赋值将导致 state 失去响应
state = { count: 1 }
赋值一个 reactive 对象<template>
{{ state }}
</template>
<script setup>
const state = reactive({ count: 0 })
// 在 nextTick 异步方法中修改 state 的值
nextTick(() => {
// 并不会触发修改 DOM ,说明失去响应了
state = reactive({ count: 11 });
});
</script>
在 nextTick 中给 state 赋值一个 reactive 的响应式对象,但是 DOM 并没有更新。let state = reactive({ count: 0 })
// state = { count: 1 }
state.count = 1
2).使用 Object.assignlet state = reactive({ count: 0 })
// state = { count: 1 },state 不会失去响应
state = Object.assign(state, { count: 1 })
3).使用 ref 定义对象let state = ref({ count: 0 })
state.value = { count: 1 }
2. 将 reactive 对象的属性赋值给变量(断开连接/深拷贝)let state = reactive({ count: 0 })
// 赋值给 n,n 和 state.count 不再共享响应性连接
let n = state.count
// 不影响原始的 state
n++
console.log(state.count) // 0
解决方案:避免将 reactive 对象的属性赋值给变量。
let state = reactive({ count: 0 })
// 普通解构,count 和 state.count 失去了响应性连接
let { count } = state
count++ // state.count 值依旧是 0
解决方案:const state = reactive({ count: 0 })
// 使用 toRefs 解构,后的属性为 ref 的响应式变量
let { count } = toRefs(state)
count.value++ // state.count 值改变为 1
二.建议:ref 一把梭<template>
{{ state.a }}
{{ state.b }}
{{ state.c }}
</template>
<script>
let state = reactive({ a: 1, b: 2, c: 3 })
onMounted(() => {
// 通过 AJAX 请求获取的数据,回显到 reactive,如果处理不好将导致变量失去响应
// 回显失败,给响应式数据赋值一个普通对象
state = { a: 11, b: 22, c: 333 }
// 回显成功,一个个属性赋值
state.a = 11
state.b = 22
state.c = 33
})
</script>
上面这个例子如果是使用 ref 进行声明,直接赋值即可,不需要将属性拆分一个个赋值。<template>
{{ state.a }}
{{ state.b }}
{{ state.c }}
</template>
<script>
let state = ref({ a: 1, b: 2, c: 3 })
onMounted(() => {
// 回显成功
state.value = { a: 11, b: 22, c: 333 }
})
</script>
给响应式对象的字面量赋一整个普通对象或 reactive 对象将导致 reactive 声明的响应式数据失去响应。