web-dev-qa-db-ja.com

vuex-関数またはオブジェクトリテラルとして返される状態

先日問題が発生し、すばらしいスタックコミュニティに解決策を求めました。

問題:

同じモジュールを他のモジュールにネストしましたが、このように状態を定義していました:

state: {
  // some state here
}

異種のモジュールの下にネストされているように見えても、すべてのモジュールが同じ状態を共有していたのです。

ソリューション

state() {
  return {
    // state here instead
  }
}

解決策は、オブジェクトリテラルとして定義するのではなく、関数の戻り状態にすることです。その理由はやや理にかなっています。これが私の質問です

新しい質問

  1. 状態がオブジェクトリテラルとして定義されているのに対し、オブジェクトリテラルを返す関数に対してストアの内部で何が起こっているのですか?

  2. なぜ関数バージョンを使用しないのですか?簡単にデフォルトの選択のように見えますが、 vuex docs for modules でも、状態をオブジェクトリテラルとして表示することを選択します。

12
Andrew Kim

tl; dr関数を使用する理由は Module Reuse


オブジェクトリテラルを返す関数ではなく、オブジェクトリテラルとして状態が定義されている場合、ストアの内部では何が起こっていますか?

そのためには、より良い 内部で確認する

var Store = function Store (options) {
  // ...
  var state = options.state; if ( state === void 0 ) state = {};
  if (typeof state === 'function') {
    state = state() || {};
  }

上記のコードは、ご覧のとおり、stateが指定されているかどうかを確認します。そうでない場合は、空のオブジェクト({})を初期stateとして割り当てます。

次に、statefunctionであったかどうかをチェックします。存在する場合は、それを実行し、返されたものをstateに割り当てます。それがundefined(または任意のfalsy値)を返した場合、再びstateに空のオブジェクト{}を割り当てます。

これがstateをオブジェクトまたは関数として提供することの違いです。提供された場合、それが実行されます。オブジェクトが提供されている場合、が直接割り当てられます


なぜ関数バージョンを使用しないのですか?これは簡単にデフォルトの選択のように見えますが、モジュールのvuexドキュメントでも、状態をオブジェクトリテラルとして表示することを選択します。

一般に、はい。オブジェクトのバージョンのほうが一般的です。通常、storeオブジェクト(およびそのstate)を宣言するのは1回だけで、Vueインスタンス。

state関数otohの使用例は Module Reuse です。

モジュールの再利用

たとえば、モジュールの複数のインスタンスを作成する必要がある場合があります。次に例を示します。

  • 同じモジュールを使用する複数のストアを作成する(たとえば、runInNewContextオプションがfalseまたは 'once'の場合、SSRで ステートフルシングルトンを回避するため )。
  • 同じモジュールを同じストアに複数回登録します。

別の可能性のあるケースは、Vuexモジュールを1回だけ宣言し、それを複数回使用しようとした場合です。異なる名前空間

上記の例は似ているので、問題を説明するための(モジュールのケースの)デモを次に示します。

const personModule = {
  namespaced: true,
  state: {name: "name"},
  mutations: {
        changeName(state, data) { state.name = data }
  }
}
const myStore = new Vuex.Store({
  strict: true,
  modules: {
    aliceNamespace: personModule,
    bobNamespcace: personModule
  }
});
new Vue({
  store: myStore,
  el: '#app',
  mounted() {
    this.changeAlicesName("Alice");
    this.changeBobsName("Bob");
  },
  computed: {
    ...Vuex.mapState('aliceNamespace', {alicesName: 'name'}),
    ...Vuex.mapState('bobNamespcace', {bobsName: 'name'})
  },
  methods: {
    ...Vuex.mapMutations('aliceNamespace', {changeAlicesName: 'changeName'}),
    ...Vuex.mapMutations('bobNamespcace', {changeBobsName: 'changeName'})
  }
})
<script src="https://unpkg.com/vue"></script>
<script src="https://unpkg.com/vuex"></script>

<div id="app">
  <p>Alice's name: {{ alicesName }}</p>
  <hr>
  <p>Bob's name: {{ bobsName }}</p>
  <hr>
  <button @click="changeAlicesName('Eve')">Change Alice's Name</button>
</div>

ご覧のとおり、状態を使用すると、同じオブジェクトが両方のモジュールのstateとして割り当てられます。これの影響は、モジュールを編集するときに、他のモジュールが影響を受けることです。実際には、2つの異なるモジュールである可能性がありますが、それらのstateは、1つの同じオブジェクトにすぎません。

一方、以下の例では、stateを関数として宣言すると、モジュール宣言を何度でも自由に再利用できます。

const personModule = {
  namespaced: true,
  state() {                     // changed to a function
    return {name: "name"}       // changed to a function
  },                            // changed to a function
  mutations: {
        changeName(state, data) { state.name = data }
  }
}
const myStore = new Vuex.Store({
  strict: true,
  modules: {
    aliceNamespace: personModule,
    bobNamespcace: personModule
  }
});
new Vue({
  store: myStore,
  el: '#app',
  mounted() {
    this.changeAlicesName("Alice");
    this.changeBobsName("Bob");
  },
  computed: {
    ...Vuex.mapState('aliceNamespace', {alicesName: 'name'}),
    ...Vuex.mapState('bobNamespcace', {bobsName: 'name'})
  },
  methods: {
    ...Vuex.mapMutations('aliceNamespace', {changeAlicesName: 'changeName'}),
    ...Vuex.mapMutations('bobNamespcace', {changeBobsName: 'changeName'})
  }
})
<script src="https://unpkg.com/vue"></script>
<script src="https://unpkg.com/vuex"></script>

<div id="app">
  <p>Alice's name: {{ alicesName }}</p>
  <hr>
  <p>Bob's name: {{ bobsName }}</p>
  <hr>
  <button @click="changeAlicesName('Eve')">Change Alice's Name</button>
</div>

stateは関数であるため、モジュールごとに異なるstateインスタンスを生成し、期待どおりに機能します。

9
acdcjunior