web-dev-qa-db-ja.com

動的に作成されたコンポーネントのvuexストアの分離

これは、私が少し立ち往生した問題でした。残念ながら、私はここで答えを見つけることができませんでした(尋ねても助けにならなかった)。そこで、いくつかの調査を行って、あちこちで尋ねたところ、この問題の解決策を得たようです。

すでに答えを知っている質問があり、他の人(自分を含む)が後でそれを見つけられるように、その知識を公に文書化したい場合。

もちろん、私の答えは理想的なものではないかもしれませんし、そうではないことを知っています。それが私が投稿している重要なポイントです-それを改善するために。

例ではアクションを使用していないことに注意してください。考え方は同じです。

問題の統計から始めましょう:

Helloという名前のローカルコンポーネントを動的に生成するApp.vueがあるとします。

<template>
  <div id="app">
    <div>
      <hello v-for="i in jobs" :key="i" :id="i"></hello>
      <button @click="addJob">New</button>
    </div>
  </div>
</template>   

<script>
import Hello from './components/Hello'

export default {
  components: {
    Hello
  }...

store.js

export const store = new Vuex.Store({
  state: {
    jobs: []
  }
})

v-forディレクティブを使用して、配列jobsを反復処理してコンポーネントを生成しています。現在のstoreは、空の配列を持つstateのみで構成されています。ボタンNewは2つのことを行う必要があります。

1)新しいコンポーネントHelloを作成します。つまり、jobsに要素を追加します(数値にします)。 <hello>keyおよびidとして割り当てられ、propsとしてローカルコンポーネントに渡されます。

2)ローカルストアを生成-modules-データのスコープを維持する新しく作成されたコンポーネント。

Hello.vue

<template>
  <div>
    <input type="number" :value="count">
    <button @click="updateCountPlus">+1</button>
  </div>
</template>

export default {
  props: ['id']
}

単純なコンポーネント-1を追加するボタンを使用した入力。

私たちの目標は、次のようなものを設計することです。 Vuex local stores

25
ogostos

NEWボタンの最初の操作では、-コンポーネントの生成-store.jsmutationを追加します

 mutations: {
    addJob (state) {
      state.jobs.Push(state.jobs.length + 1)
...
}

第二に、ローカルモジュールの作成。ここでは、reusableModuleを使用してモジュールの複数のインスタンスを生成します。このモジュールは、利便性のために別のファイルに保存されています。また、モジュールの状態を宣言するための関数の使用に注意してください

const state = () => {
  return {
    count: 0
  }
}

const getters = {
  count: (state) => state.count
}

const mutations = {
  updateCountPlus (state) {
    state.count++
  }
}

export default {
  state,
  getters,
  mutations
}

reusableModuleを使用するには、それをインポートし、動的モジュール登録を適用します。

store.js

import module from './reusableModule'

const {state: stateModule, getters, mutations} = module

export const store = new Vuex.Store({
  state: {
    jobs: []
  },
  mutations: {
    addJob (state) {
      state.jobs.Push(state.jobs.length + 1)
      store.registerModule(`module${state.jobs.length}`, {
        state: stateModule,
        getters,
        mutations,
        namespaced: true // making our module reusable
      })
    }
  }
})

その後、Hello.vueをそのストレージにリンクします。 stateからgettersmutationsactionsvuexが必要になる場合があります。ストレージにアクセスするには、gettersを作成する必要があります。 mutationsと同じです。

Home.vue

<script>

export default {
  props: ['id'],
  computed: {
     count () {
        return this.$store.getters[`module${this.id}/count`]
     }
  },
  methods: {
    updateCountPlus () {
        this.$store.commit(`module${this.id}/updateCountPlus`)
     } 
  }
}
</script>

gettersmutationsactionsがたくさんあると想像してください。なぜ{mapGetters}または{mapMutations}を使用しないのですか?複数のモジュールがあり、必要なモジュールへのパスがわかっている場合は、それを実行できます。残念ながら、モジュール名にはアクセスできません。

コードは、コンポーネントの作成時ではなく、コンポーネントのモジュールの実行時(アプリの起動時)に実行されます。したがって、これらのヘルパーは、事前にモジュール名を知っている場合にのみ使用できます。

ここにはほとんど助けがありません。 gettersmutationsを分離し、それらをオブジェクトとしてインポートして、きれいに保つことができます。

<script>
import computed from '../store/moduleGetters'
import methods from '../store/moduleMutations'

export default {
  props: ['id'],
  computed,
  methods
}
</script>

Appコンポーネントに戻ります。 mutationをコミットする必要があります。また、getter用にいくつかのAppを作成しましょう。モジュールにあるデータにアクセスする方法を示すため。

store.js

export const store = new Vuex.Store({
  state: {
    jobs: []
  },
  getters: {
    jobs: state => state.jobs,
    sumAll (state, getters) {
      let s = 0
      for (let i = 1; i <= state.jobs.length; i++) {
        s += getters[`module${i}/count`]
      }
      return s
    }
  } 
...

Appコンポーネントの仕上げコード

<script>
import Hello from './components/Hello'
import {mapMutations, mapGetters} from 'vuex'

    export default {
      components: {
        Hello
      },
      computed: {
        ...mapGetters([
          'jobs',
          'sumAll'
        ])
      },
      methods: {
        ...mapMutations([
          'addJob'
        ])
      }
    }
    </script>
20
ogostos

こんにちは、質問と解決策を投稿していただきありがとうございます。

私は数日前にVuexを学び始め、同様の問題に遭遇しました。私はあなたのソリューションをチェックし、新しいモジュールを登録する必要のない私のものを思いつきました。私はそれがかなりやり過ぎだと思うし、正直に言うと、なぜあなたがそれをするのか理解していない。私が問題を誤解した可能性は常にあります。

マークアップのコピーを作成しましたが、わかりやすくするためにいくつかの違いがあります。

私が持っている:

  1. JobList.vue-メインのカスタムコンポーネント
  2. Job.vue-ジョブリストの子カスタムコンポーネント
  3. jobs.js-vuexストアモジュールファイル

JobList.vue(ジョブリストアイテムのラッピングを担当)

<template>
    <div>
        <job v-for="(job, index) in jobs" :data="job" :key="job.id"></job>

        <h3>Create New Job</h3>
        <form @submit.prevent="addJob">
            <input type="text" v-model="newJobName" required>
            <button type="submit">Add Job</button>
        </form>
    </div>
</template>

<script>
    import store from '../store/index'
    import job from './job';

    export default {
        components: { job },
        data() {
            return {
                newJobName: ''
            };
        },
        computed: {
            jobs() {
                return store.state.jobs.jobs;
            }
        },
        methods: {
            addJob() {
                store.dispatch('newJob', this.newJobName);
            }
        }
    }
</script>

仕事

<template>
    <div>
        <h5>Id: {{ data.id }}</h5>
        <h4>{{ data.name }}</h4>
        <p>{{ data.active}}</p>
        <button type="button" @click="toggleJobState">Toggle</button>
        <hr>
    </div>
</template>

<script>

    import store from '../store/index'

    export default {
        props: ['data'],
        methods: {
            toggleJobState() {
                store.dispatch('toggleJobState', this.data.id);
            }
        }
    }

</script>

最後に、jobs.js Vuexモジュールファイル:

export default {
    state: {
        jobs: [
            {
                id: 1,
                name: 'light',
                active: false
            },
            {
                id: 2,
                name: 'medium',
                active: false
            },
            {
                id: 3,
                name: 'heavy',
                active: false
            }
        ]
    },

    actions: { //methods
        newJob(context, jobName) {
            context.state.jobs.Push({
                id: context.getters.newJobId,
                name: jobName,
                active: false
            });
        },
        toggleJobState(context, id) {
            context.state.jobs.forEach((job) => {
                if(job.id === id) { job.active = !job.active; }
            })
        }
    },

    getters: { //computed properties
        newJobId(state) { return state.jobs.length + 1; }
    }
}

ストアに新しいジョブを追加することができます。「アクティブ」プロパティが示すように、新しいカスタムvuexモジュールを必要とせずに個々のジョブをすべて制御できます。

2
Vlada