【问题标题】:Vuex: Using new store for large section of same app?Vuex:为同一应用程序的大部分使用新商店?
【发布时间】:2020-07-15 19:11:35
【问题描述】:

我有一个store.js,我在我的主应用程序中注入如下:

new Vue({
    vuetify: new Vuetify(opts),
    store,
    el: "#app",
    },
});

我的商店的形状如下,但里面有很多数据:

store.js

export default new Vuex.Store({
   state: {},
   getters: {},
   mutations: {},
});

我现在正在处理的同一个应用程序中有一个相当大的组件,它有很多状态。有没有办法在不改变现有商店结构的情况下创建自己的新商店或文件?
我在想是否有办法将 2 个商店注入应用程序,这可能会有所帮助,但我不确定这是否可能。

【问题讨论】:

标签: vue.js vuex


【解决方案1】:

您可以使用Vuex modules

如何向 VueX 添加模块

在顶部链接的页面上的解释非常简单,但是 sn-p 可能有助于更好地理解它:

// define a module
const moduleA = {
  state: () => ({
    titleText: 'This is a Vuex module/namespace snippet',
    items: [
      'item 1',
      'item 2',
      'item 3'
    ],
  }),

  mutations: {
    ADD_ITEM(state) {
      let { items } = JSON.parse(JSON.stringify(state))
      const nextItem = `item ${ items.length + 1 }`
      items.push(nextItem)
      state.items = items
    }
  },

  actions: {
    addItem({ commit }) {
      commit('ADD_ITEM')
    }
  },

  getters: {
    getItems: ({ items }) => items,
    filterItem: ({ items }) => item => {
      return items.find(e => e === item)
    }
  }
}

// define the root store, and add the module to it
const store = new Vuex.Store({
  state: {
    rootItems: [
      'root item 1',
      'root item 2'
    ]
  },
  modules: {
    moduleA: {
      namespaced: true, // setting namespaced
      ...moduleA // spreading the module
    }
  }
})

new Vue({
  el: "#app",
  store, // only the root store is added here!
  computed: {
    items() {
      // this getter is called in the namespace of the module
      return this.$store.getters['moduleA/getItems']
    },
    filteredItem() {
      // this getter is called in the namespace of the module and a parameter
      return this.$store.getters['moduleA/filterItem']('item 1')
    },
    title() {
      // this state is called in the namespace of the module
      return this.$store.state.moduleA.titleText
    },
    rootItems() {
      // this state is from the root store - no namespace
      return this.$store.state.rootItems
    },
    mergedList() {
      // you can mix-n-match the stores here (of course it could be solved inside Vuex - but that's a bit trickier :) )
      return [...this.items, ...this.rootItems]
    }
  },
  methods: {
    addItem() {
      // the action is dispatched in the namespace of the module
      this.$store.dispatch('moduleA/addItem')
    }
  }
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<script src="https://unpkg.com/vuex"></script>
<div id="app">
  <div>{{ title }}</div>
  <hr />
  <div>MODULEA FILTERED ITEM:</div>
  <div>{{ filteredItem }}</div>
  <hr />
  <div>MODULEA ITEM LIST:</div>
  <div v-for="item in items" :key="item">
    {{ item }}
  </div>
  <button @click="addItem">ADD ITEM</button>
  <hr />
  <div>ROOT ITEM LIST:</div>
  <div v-for="item in rootItems" :key="item">
    {{ item }}
  </div>
  <hr />
  <div>MERGED ITEM LIST:</div>
  <div v-for="item in mergedList" :key="item">
    {{ item }}
  </div>
  <hr />
</div>

我试着把基本的想法放在上面的sn-p中:

  • 从命名空间 Vuex 模块中映射状态值

  • 从根 Vuex 存储映射状态值

  • 在命名空间 Vuex 模块中映射带有和不带有参数的 getter

  • 调度命名空间 Vuex 模块的操作

从这里,您可以看到添加一个模块正是您要寻找的:保留已经存在的商店并在其中添加另一个。

建议

  1. Vuex 模块不需要命名空间,但强烈建议使用。它们可能会使您的代码更长一些(在命名空间中调用事物),但会使逻辑更加更简洁。
  2. 如果您为模块使用单独的文件,整个事情看起来会有些不同 - 只有这种情况无法在 StackOverflow 上显示。您需要 export Vuex 模块并将它们导入您的根存储(或进行自动导入 - 这里给出了一种解决方案:Architecting Vuex store for large scale Vue.js applications
  3. 如果您有一个巨大的store,您可以使用此方法将其分解为逻辑模块,或者您可以将statemutationsactionsgetters 分隔在不同的文件中。李>

TL;DR

将模块添加到您的store

// store.js
import Vue from 'vue';
import Vuex from 'vuex';
import { moduleA } from './moduleA'

Vue.use(Vuex);

const initialState = () => ({})

const state = initialState()
const mutations = {}
const actions = {}
const getters = {}

export default new Vuex.Store({
  state,
  mutations,
  actions,
  getters,
  modules: {
    moduleA
  },
});

创建并导出您的模块(以便根存储可以导入它):

// moduleA.js
const initialState = () => ({})

const state = initialState()
const mutations = {}
const actions = {}
const getters = {}

export const moduleA = {
  namespaced: true,
  state,
  mutations,
  actions,
  getters
}

【讨论】:

  • 对此的所有答案都很棒,但这个答案帮助我通过示例进行了设置。谢谢!
  • @raulInsto 我很高兴能提供帮助。
【解决方案2】:

使用模块可以降低应用程序的复杂性。我以这种方式在我的项目中使用 vuex:

文件夹结构:

src
--components/ => folder
--store/ => folder
--App.vue
--main.js

让我们看看 main.js 文件:

import Vue from 'vue';
import App from './App.vue'
// Import the index.js file from the store folder
import store from '@/store/index';

new Vue({
  store,
  render: h => h(App)
}).$mount('#app')

现在让我们检查商店文件夹结构

store/
--index.js
--moduleA/ => folder
--moduleB/ => folder

store文件夹中的index.js文件

import Vue from 'vue';
import Vuex from 'vuex';
import moduleA from './moduleA'; // By default imports index.js file inside moduleA folder 
import moduleB from './moduleB'; // By default imports index.js file inside moduleB folder

Vue.use(Vuex);
export default new Vuex.store({
  modules: {
    moduleA,
    moduleB
  }
});

最后,让我们创建我们的模块,moduleA文件夹结构(moduleB相同):

moduleA/ => folder
--index.js
--actions.js
--mutations.js
--getters.js

actions.js 文件:

function someAction({ commit }, payload) {
  commit("someMutation", 'newValue');
}

export default {
  someAction
}

mutations.js 文件:

function someMutation(state, payload) {
  state.someStateVariable = payload;
}

export default {
  someMutation
}

getters.js

export default {
  getSomeStateVariable: state => state.someStateVariable
}

最后是 index.js 文件

import actions from './actions';
import getters from './getters'
import mutations from './mutations';

const state = {
  someStateVariable: 'initial value'
}

export default {
  actions,
  getters,
  mutations,
  namespaced: true, // allows to use namespace in the components
  state
}

对模块 B 重复,如果需要,对任何其他模块重复

我们已经准备好在我们的组件中使用 store 模块了:

<template>
  <div>
    {{ someStateVariable }}
    <button @click="setAValue">Set a new value</button>
  </div>
</template>
<script>
import { mapActions, mapGetters} from 'vuex';
export default{
  name: "AComponent",
  computed: {
    ...mapGetters({
      // You can set any name as key, but the way to access the getter is
      // with a string with the format "moduleName/getterName"
      someStateVariable: "moduleA/getSomeStateVariable"
    })
  },
  methods: {
    ...mapActions({
      // Same as mapGetters
      someAction: "moduleA/someAction"
    }),
    setAValue() {
      // Actions within the mapActions helpers, can be accessed as local
      // methods
      this.someAction("A new value for the someStateVariable")
    }
  }
}
</script>

这是很多信息,我知道,所以如果有不清楚的地方,请告诉我,我会进一步解释。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-08-28
    • 2017-12-16
    • 1970-01-01
    • 1970-01-01
    • 2013-10-23
    • 2016-04-14
    相关资源
    最近更新 更多