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

And*_*Kim 11 javascript vue.js vuex vuejs2

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

问题:

我在其他模块中嵌套了相同的模块,但我以这种方式定义状态:

state: {
  // some state here
}
Run Code Online (Sandbox Code Playgroud)

发生的事情是我的所有模块,尽管看起来嵌套在不同的模块下,所有模块都共享相同的状态.

解决方案

state() {
  return {
    // state here instead
  }
}
Run Code Online (Sandbox Code Playgroud)

解决方案是具有函数返回状态,而不是将其定义为对象文字.为什么有些有道理.这是我的问题

新问题

  1. 当状态被定义为对象文字而不是返回对象文字的函数时,在商店的引擎下发生了什么?

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

acd*_*ior 10

tl; dr使用函数的原因是模块重用.


当状态被定义为对象文字而不是返回对象文字的函数时,在商店的引擎下发生了什么?

为此,更好地检查引擎盖:

var Store = function Store (options) {
  // ...
  var state = options.state; if ( state === void 0 ) state = {};
  if (typeof state === 'function') {
    state = state() || {};
  }
Run Code Online (Sandbox Code Playgroud)

如您所见,上面的代码会检查是否state提供了代码.如果不是,则将空对象({})指定为初始对象state.

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

这就是提供state作为对象或函数之间的区别:如果提供了一个,则执行它.如果提供了对象,则直接分配.


你为什么不用功能版?它似乎很容易成为默认选择,但即使在模块的vuex文档中,它们也选择将状态显示为对象文字.

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

state函数otoh的用例是模块重用:

模块重用

有时我们可能需要创建模块的多个实例,例如:

  • 创建使用相同模块的多个商店(例如,当runInNewContext选项为false或"一次"时,避免 SSR中的有状态单例);
  • 在同一商店中多次注册同一模块.

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

由于上面的例子是类似的,这里是一个演示(模块案例)来说明问题:

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'})
  }
})
Run Code Online (Sandbox Code Playgroud)
<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>
Run Code Online (Sandbox Code Playgroud)

如您所见,当我们使用状态时,将为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'})
  }
})
Run Code Online (Sandbox Code Playgroud)
<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>
Run Code Online (Sandbox Code Playgroud)

因为它state是一个函数,它将state为每个模块生成一个不同的实例,一直按预期工作.