使用Vuex,当项目是对象数组的一部分时如何从项目中删除项目?

时间:2019-08-26 23:01:01

标签: javascript vue.js vuejs2 vuex

在此处参考实时演示代码:

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.vue向下传递category.items Item.vue作为每个项目的道具。

当单击项目旁边的删除按钮时,我需要删除该项目:

enter image description here

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

我可以想到两种方式:

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

    < / li>
  2. Item.vueCategory.vue发出一个事件,并让Category.vue处理Vuex调用以进行删除。这样一来,类别和要删除的项目就都知道了。

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

2 个答案:

答案 0 :(得分:1)

我强烈建议(2)。通常,如果您可以创建一个接受道具并发出事件的组件,而没有其他副作用(API调用,Vuex突变等),则通常是正确的路径。在这种情况下,您甚至可以将事件完全推送回父级的父级。

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

在此处发出事件的另一个好处是,您可以更轻松地使用storybook之类的工具,而不必处理任何Vuex解决方法。

答案 1 :(得分:0)

我个人希望使用2(发出从Item.vueCategory.vue的事件),但是,由于您询问了可能性,因此还有第三种方法:传递< strong>回调功能

示例:

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