Vuex - 更新整个数组

时间:2018-06-08 19:21:27

标签: javascript vue.js vuex

我有一个Vue.js应用程序。这个应用程序使用Vuex进行状态管理。我的商店看起来像这样:

const store = new Vuex.Store({
    state: {
        items: []
    },

    mutations: {
        MUTATE_ITEMS: (state, items) => {
            state.items = items;
        }
    },

    actions: {
        loadItems: (context, items) => {
            context.commit('MUTATE_ITEMS', items);
        }
    }
  })
;

在我的Vue实例中,我有以下方法:

loadItems() {

  let items = [];
  for (let I=0; I<10; I++) {
    items.push({ id:(I+1), name: 'Item #' + (I+1) });
  }
  this.$store.dispatch('loadItems', items);
},

当我运行它时,我注意到我的子组件中的项目列表没有得到更新。我怀疑这是因为Vue.js中的反应模型。但是,我不确定如何更新整个阵列。另外,我不确定是否需要在我的商店变异,存储操作或Vue实例方法本身中使用Vue.set。我有点困惑。

组件:

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

如何在Vue.js应用中更新集中存储在Vuex中的整个数组?

4 个答案:

答案 0 :(得分:10)

使用vue的set功能。这将确保Vue的反应性开始并更新所需的对象。

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);
        }
    }
  })
;

在处理数组或对象时,防止可变性是一个好主意,我通常使用扩展运算符{...myObject}[..myArray],这将阻止对象从其他来源的更改要改变你的来源,所以在吸气剂中实施也是个好主意。

更新

以下是一个工作示例:https://codesandbox.io/s/54on2mpkn(codesandbox允许您拥有单个文件组件)

我注意到的事情是你没有 getters ,这些有助于获取数据。您可以直接使用计算值或使用mapGetters调用它们。但它们不是强制性的。您可以通过以下三种方式获取数据

<script>
import { mapGetters } from "vuex";
import Item from "./Item";

export default {
  name: "ItemList",
  components: {
    Item
  },
  computed: {
    ...mapGetters(["items"]), // <-- using magGetters
    itemsGet() {    // <-- using getter, but not mapGetters
      return this.$store.getters.items;
    },
    itemsDirect() {  // <--no getter, just store listener
      return this.$store.state.items;
    }
  }
};
</script>

从功能角度来看,选择哪一个并不重要,但使用getter可以获得更易维护的代码。

答案 1 :(得分:1)

您需要像以下任何一样调度操作:

// dispatch with a payload
this.$store.dispatch('loadItems', {items})

// dispatch with an object
this.$store.dispatch({type: 'loadItems',items})

答案 2 :(得分:0)

我遇到了类似的问题,并且解决了以下问题://在组件中

计算:{

 data: {
     get() {
         this.$store.commit('updateData', this.$store.state.data)
         return this.$store.state.data;
     },
 }

} //在商店中

 mutations: {
      updateData(state,item){
          store.state.data = item;
      }
  }

是的,这太神奇了。

答案 3 :(得分:0)

如果您在 2021 年找到了这个答案,并且正在使用 Vuex 4、Vue 3、Typescript、setup() 函数(也称为 Composition API),那么以下是我解决类似问题的方法。

>

最初我通过异步操作在 vuex 状态下改变数组并且没有看到 UI 更改传播。所以这是假装。

我有一个像这样的 vuex 状态

interface State {
  areas: Area[]
}

这样的组件

export default {
   name: "Area",
   setup() {
      const store = UseStore();
      store.dispatch('fetchAreas');
      const areas = store.state.areas;
      return {
        store,
        areas,
      }
   }
}

那个动作的调度函数是这样的

async ['fetchAreas](context: ContextType<State>): Promise<void> {
   const areas = await getTheStuff();
   context.commit('setAreas', areas);
} 

这是假的

我的问题是'setAreas'的变异接收器

原来是这样的

['setAreas'](state: State, value: Area[]) {
  state.areas = value;
}

并且未能触发 ui 更新。 我改成这个

['setAreas'](state: State, value: Area[]) {
   state.areas.splice(0, state.areas.length);
   value.forEach(v => state.areas.push(v));
}

这触发了 UI 更新。 为什么?

我相信,通过最初覆盖整个数组,vuex 通过反应性进行的更改检测丢失了对原始数组的引用,因此组件因此在 vuex 重新注册新数组以使其成为反应性时不会发生任何变化。

第二种方法利用数组方法,将原始数组引用保持在原位,但完全更新其元素。它效率不高,但有效,有时,这就是我们所希望的。