响应式的丢失
- reactive
const arr = reactive([]);
const load = () => {
const res = [2, 3, 4, 5]; //假设请求接口返回的数据
// 方法1 失败,直接赋值丢失了响应性
// arr = res;
// 方法2 这样也是失败
// arr.concat(res);
// 方法3 可以,但是很麻烦
res.forEach(e => {
arr.push(e);
});
};
问题原因:这是因为 arr = newArr这行代码让arr失去了响应式。vue3 使用proxy,对于对象和数组都不能直接整个赋值。
具体原因:reactive声明的响应式对象被 arr 代理,操作代理对象需要有代理对象的前缀,直接覆盖会丢失响应式。
- 方法2为什么不行?只有push或者根据索引遍历赋值才可以保留reactive数组的响应性?
// 这几种办法都可以触发响应性,推荐第一种
// 方案1:创建一个响应式对象,对象的属性是数组
const state = reactive({
arr: []
});
state.arr = [1, 2, 3]
// 方案2: 使用ref函数
const state = ref([])
state.value = [1, 2, 3]
// 方案3: 使用数组的push方法
const arr = reactive([])
arr.push(...[1, 2, 3])
- 使用ref定义一个响应式的数组时,此时你的数组时响应式的,但是当你对数组做push等方法时,就失去响应式了,
- 这是因为在 Vue 的响应式系统中,属性的添加或删除被视为改变原始对象的引用,而不是改变原始对象本身。
reactive 操作
<template>
<div>
<button @click="addItem(1)">添加 id 1 的对象</button>
<button @click="addItem(2)">添加 id 2 的对象</button>
<button @click="updateItem(1, 'name', 'Updated Name')">更新 id 1 的 name</button>
<button @click="removeItem(2)">删除 id 2 的对象</button>
<ul>
<li v-for="(item, index) in arrayData" :key="index">
<strong>Item {{ index + 1 }}:</strong>
<ul>
<li v-for="(value, key) in item" :key="key">{{ key }}: {{ value }}</li>
</ul>
</li>
</ul>
</div>
</template>
<script setup>
import { reactive } from 'vue';
// 创建一个响应式数组,每个元素是一个对象
const arrayData = reactive([]);
// 添加一个新的对象
const addItem = (id) => {
const newItem = {
id,
name: `Item ${id}`,
description: `Description for item ${id}`,
};
arrayData.push(newItem); // 将新的对象添加到数组中
};
// 更新对象中的值
const updateItem = (id, key, newValue) => {
// 找到对应的对象
const item = arrayData.find((item) => item.id === id);
if (item) {
item[key] = newValue; // 更新指定键的值
} else {
console.warn(`Item with id ${id} not found`);
}
};
// 删除对象
const removeItem = (id) => {
// 找到并删除对应的对象
const index = arrayData.findIndex((item) => item.id === id);
if (index !== -1) {
arrayData.splice(index, 1); // 从数组中删除对象
} else {
console.warn(`Item with id ${id} not found`);
}
};
</script>
使用 ref 操作数组中的对象
<template>
<div>
<button @click="addItem(1)">添加 id 1 的对象</button>
<button @click="addItem(2)">添加 id 2 的对象</button>
<button @click="updateItem(1, 'name', 'Updated Name')">更新 id 1 的 name</button>
<button @click="removeItem(2)">删除 id 2 的对象</button>
<ul>
<li v-for="(item, index) in arrayData.value" :key="index">
<strong>Item {{ index + 1 }}:</strong>
<ul>
<li v-for="(value, key) in item" :key="key">{{ key }}: {{ value }}</li>
</ul>
</li>
</ul>
</div>
</template>
<script setup>
import { ref } from 'vue';
// 使用 ref 包裹数组,初始值为空数组
const arrayData = ref([]);
// 添加一个新的对象
const addItem = (id) => {
const newItem = {
id,
name: `Item ${id}`,
description: `Description for item ${id}`,
};
arrayData.value.push(newItem); // 使用 .value 访问和修改 ref 包裹的数组
};
// 更新对象中的值
const updateItem = (id, key, newValue) => {
const item = arrayData.value.find((item) => item.id === id);
if (item) {
item[key] = newValue; // 修改对象的指定字段
} else {
console.warn(`Item with id ${id} not found`);
}
};
// 删除对象
const removeItem = (id) => {
const index = arrayData.value.findIndex((item) => item.id === id);
if (index !== -1) {
arrayData.value.splice(index, 1); // 从数组中删除对象
} else {
console.warn(`Item with id ${id} not found`);
}
};
</script>
- 使用 ref 处理数组:当使用 ref 来处理数组时,访问和修改数组元素需要使用
.value
。对于数组中的对象,你可以直接操作这些对象的属性。 - reactive 和 ref 的区别:reactive 通常用于处理深层次嵌套的复杂对象或数组,而 ref 更适用于单一对象或基础数据类型。使用 ref 时,需要特别注意对数据的访问方式(需要使用
.value
)。