vuex- 状态作为函数或对象文字返回

vuex- state returned as function or object literal

前几天我 运行 遇到了一个问题,并向伟大的堆栈社区寻求解决方案。

问题:

我在其他模块中嵌套了相同的模块,但我是这样定义状态的:

state: {
  // some state here
}

发生的事情是我的所有模块,尽管它们似乎嵌套在不同的模块下,但都共享相同的状态。

解决方案

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

解决方案是使用函数 return 状态而不是将其定义为对象文字。为什么有点道理。这是我的问题

新问题

  1. 当 state 被定义为对象字面量与函数 returning 对象字面量时,store 的底层发生了什么?

  2. 为什么你永远不用功能版?这似乎很容易成为默认选择,但即使在 vuex docs for modules 中,他们也选择将状态显示为对象文字。

tl;dr 使用函数的原因是Module Reuse.


What is happening under the hood of the store when state is defined as an object literal versus a function returning an object literal?

为此,更好 check under the hood:

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

如您所见,上面的代码检查是否提供了 state。如果不是,它将分配一个空对象 ({}) 作为初始 state.

接下来它检查 state 是否是 function。如果是,则执行它并将返回的内容分配给 state。如果它返回 undefined(或任何 falsy 值),它再次分配给 state 空对象 {}.

这就是将 state 作为对象或函数提供的区别:如果提供了,就会执行。如果提供了对象,则直接赋值


Why would you ever not use the function version? It seems like easily the default choice, but even in vuex docs for modules, they opt to show state as an object literal.

一般来说,是的,对象版本可能更常见,因为您通常只声明 store 对象(及其 state)一次,然后在您的 Vue 实例中使用它。

state 函数 otoh 的一个用例是 Module Reuse:

Module Reuse

Sometimes we may need to create multiple instances of a module, for example:

  • Creating multiple stores that use the same module (e.g. To avoid stateful singletons in the SSR when the runInNewContext option is false or 'once');
  • Register the same module multiple times in the same store.

另一种可能的情况是,如果您 只声明了一个 Vuex 模块一次 并试图在不同的命名空间下 使用它多次 .

上面的例子很相似,这里有一个demo(模块案例)来说明问题:

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。这样做的效果是当我们编辑一个模块时,另一个会受到影响。实际上,它们可能是两个不同的模块,但它们的state只是一个相同的对象

另一方面,在下面的示例中,当我们将 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实例,一路按预期工作。