web-dev-qa-db-ja.com

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に一元的に保存されている配列全体を更新するにはどうすればよいですか?

7
Some User

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を使用して呼び出すことができます。しかし、それらは必須ではありません。データを取得する3つの方法を次に示します

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

機能の観点からどちらを選択したかは関係ありませんが、ゲッターを使用すると、よりメンテナンスしやすいコードになります。

17
Daniel

次のいずれかのようなアクションをディスパッチする必要があります。

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

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