问题
I have a Vue.js app. This app is using Vuex for state management. My store looks like this:
const store = new Vuex.Store({
state: {
items: []
},
mutations: {
MUTATE_ITEMS: (state, items) => {
state.items = items;
}
},
actions: {
loadItems: (context, items) => {
context.commit('MUTATE_ITEMS', items);
}
}
})
;
In my Vue instance, I have the following method:
loadItems() {
let items = [];
for (let I=0; I<10; I++) {
items.push({ id:(I+1), name: 'Item #' + (I+1) });
}
this.$store.dispatch('loadItems', items);
},
When I run this, I notice that the item list in my child components are not getting updated. I suspect this is because of the reactivity model in Vue.js. However, I'm not sure how to update an entire array. In addition, I'm not sure if I need to use Vue.set
in my store mutation, store action, or in the Vue instance method itself. I'm slightly confused.
Component:
<template>
<div>
<h1>Items ({{ items.length }})</h1>
<table>
<tbody>
<tr v-for="item in items" :key="item.id">
<td>{{ item.id }}</td>
</tr>
</tbody>
</table>
</div>
</template>
<script>
import { mapState } from 'vuex';
export default {
computed: mapState({
items: state => state.items
})
};
</script>
How do I update an entire Array that is centrally stored in Vuex in a Vue.js app?
回答1:
use vue's set
function. This will make sure that the Vue's reactivity kicks in and updates the required objects.
import Vuex from 'vuex';
const store = new Vuex.Store({
state: {
items: []
},
mutations: {
MUTATE_ITEMS: (state, items) => {
Vue.set(state, 'items', items);
// or, better yet create a copy of the array
Vue.set(state, 'items', [...items]);
}
},
actions: {
loadItems: (context, items) => {
context.commit('MUTATE_ITEMS', items);
}
}
})
;
When dealing with arrays or Objects, it's a good idea to prevent mutability, which I usually do with a spread operator {...myObject}
or [..myArray]
this will prevent changes to the object from other source to change your source, so it's a good idea to implement in getters too.
Update:
Here is a working example: https://codesandbox.io/s/54on2mpkn (codesandbox allows you to have single file components)
The thing I noticed is that you don't have any getters, those help get the data. You can call them using computed values directly, or using mapGetters. but they are not mandatory. Here are three ways you can get the data
<script>
import { mapGetters } from "vuex";
import Item from "./Item";
export default {
name: "ItemList",
components: {
Item
},
computed: {
...mapGetters(["items"]), // <-- using mapGetters
itemsGet() { // <-- using getter, but not mapGetters
return this.$store.getters.items;
},
itemsDirect() { // <--no getter, just store listener
return this.$store.state.items;
}
}
};
</script>
it doesn't matter which one you chose from the functionality standpoint, but using getters makes for more maintainable code.
回答2:
You need to dispatch action like any of the following:
// dispatch with a payload
this.$store.dispatch('loadItems', {items})
// dispatch with an object
this.$store.dispatch({type: 'loadItems',items})
来源:https://stackoverflow.com/questions/50767191/vuex-update-an-entire-array