【问题标题】:Using Vuex, how do I remove items from an array when they are part of an array of objects?使用 Vuex,当它们是对象数组的一部分时,如何从数组中删除它们?
【发布时间】:2019-12-31 02:44:44
【问题描述】:

在此参考现场演示代码:

https://codesandbox.io/s/vue-template-r26tg

假设我有一个包含以下数据的 Vuex 商店:

const store = new Vuex.Store({
  state: {
    categories: [
      {
        name: "Category A",
        items: [{ name: "Item 1" }, { name: "Item 2" }, { name: "Item 3" }]
      },
      {
        name: "Category B",
        items: [{ name: "Item A" }, { name: "Item B" }, { name: "Item C" }]
      },
      {
        name: "Category C",
        items: [{ name: "Item !" }, { name: "Item @" }, { name: "Item #" }]
      }
    ]
  }
});

我有一个 App.vueCategory.vueItem.vue,它们的设置是这样的:

//App.vue
<template>
  <div id="app">
    <Category v-for="(category, index) in categories" :category="category" :key="index"/>
  </div>
</template>

<script>
  export default {
    components: { Category },

    computed: {
      ...mapState(["categories"])
    }
  };
</script>
//Category.vue
<template>
  <div class="category">
    <div class="header">{{ category.name }}</div>
    <Item v-for="(item, index) in category.items" :item="item" :key="index"/>
  </div>
</template>

<script>
  export default {
    components: { Item },

    props: {
      category: { type: Object, required: true }
    }
  };
</script>
//Item.vue
<template>
  <div class="item">
    <div class="name">{{ item.name }}</div>
    <div class="delete" @click="onDelete">&#10006;</div>
  </div>
</template>

<script>
  export default {
    props: {
      item: { type: Object, required: true }
    },

    methods: {
      onDelete() {
        this.$store.commit("deleteItem", this.item);
      }
    }
  };
</script>

换句话说,App.vue 从 Vuex 获取类别列表,然后将其传递给 Category.vue 作为每个类别的道具,然后 Category.vuecategory.items 传递给 Item.vue 作为道具每个项目。

当点击旁边的删除按钮时,我需要删除一个项目:

但是,在Item.vue 级别,我只能访问item,但不能访问category。如果我将 item 发送到 Vuex,我无法判断它属于哪个 category。如何获取对 category 的引用,以便我可以使用 Vuex 从中删除项目?

我可以想到两种方法:

  1. 为每个item 将父引用添加回category。这是不可取的,不仅因为我必须处理 item 数据,还因为它引入了一个循环引用,我不想在应用程序的其他部分处理它。

  2. Item.vueCategory.vue 发出一个事件,让Category.vue 处理删除的Vuex 调用。这样类别和要删除的项都是已知的。

有没有更好的方法来处理这种删除?

【问题讨论】:

    标签: javascript vue.js vuejs2 vuex


    【解决方案1】:

    我强烈推荐 (2)。一般来说,如果你可以创建一个组件,它接受 props 并发出事件而没有其他副作用(API 调用、Vuex 突变等),那通常是正确的路径。在这种情况下,您甚至可以将事件一直推送回父级的父级。

    共享状态 (Vuex) 真正 有帮助的地方是当您在 DOM 树中有两个或多个彼此远离的组件时。例如。想象一个包含总项目计数的标题。这种程度的空间分离可能存在于您的应用中,但在这个简单的示例中并不存在。

    在此处发出事件的另一个好处是,您可以更轻松地使用 storybook 等工具,而无需处理任何 Vuex 变通方法。

    【讨论】:

      【解决方案2】:

      就个人而言,我会选择 2(从 Item.vueCategory.vue 发出一个事件),但是,由于您询问了可能性,还有第三种方法:传递一个 回调函数.

      例子:

      Category.vue:

      <template>
        <div class="category">
          <div class="header">{{ category.name }}</div>
          <Item v-for="(item, index) in category.items" :item="item" :key="index"
           :on-delete="deleteItem"/>
        </div>
      </template>
      
      <script>
      // ...
      export default {
        // ...
        methods: {
          deleteItem(i) {
            console.log('cat', this.category.name, 'item', i)
            //this.$store.commit("deleteItem", this.item);
          }
        }
      };
      </script>
      

      Item.vue:

      <template>
        <div class="item">
          <div class="name">{{ item.name }}</div>
          <div class="delete" @click="() => onDelete(this.item)">&#10006;</div>
        </div>
      </template>
      
      <script>
      export default {
        props: {
          item: { type: Object, required: true },
          onDelete: { type: Function }
        },
      };
      </script>
      

      Updated sandbox here。注意,在这种情况下,回调是onDelete

      如果这是 React,那么回调肯定是一种更惯用的方式。如前所述,在 Vue 中,我主张在子级中发出 事件 并在父级中处理它(使用v-on)。

      【讨论】:

      • 当然,你也可以在Category.vue中声明::on-delete="deleteItem(item)",这样就更接近于事件选项了。
      猜你喜欢
      • 2011-05-19
      • 2011-10-25
      • 2020-06-12
      • 2020-07-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多