响应式的丢失

  • 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)。