Nuxt + Vuex - How do I break down a Vuex module into separate files?
I am using nuxt 2.1.0
If you want to have something like this :
In my store/index.js
Make sure you have namespaced: true
import Vuex from 'vuex';import apiModule from './modules/api-logic';import appModule from './modules/app-logic';const createStore = () => { return new Vuex.Store({ namespaced: true, modules: { appLogic: appModule, api: apiModule } });};export default createStore
In moduleOne
In my store/api-logic/index.js
import actions from './actions';import getters from './getters';import mutations from './mutations';const defaultState = { hello: 'salut I am module api'}const inBrowser = typeof window !== 'undefined';// if in browser, use pre-fetched state injected by SSRconst state = (inBrowser && window.__INITIAL_STATE__) ? window.__INITIAL_STATE__.page : defaultState;export default { state, actions, mutations, getters}
In my store/api-logic/getters.js
export default { getHelloThere: state => state.hello}
In module Two
In my store/app-logic/index.js
import actions from './actions';import getters from './getters';import mutations from './mutations';const defaultState = { appLogicData: 'bonjours I am module Logic'}const inBrowser = typeof window !== 'undefined';// if in browser, use pre-fetched state injected by SSRconst state = (inBrowser && window.__INITIAL_STATE__) ? window.__INITIAL_STATE__.page : defaultState;export default { state, actions, mutations, getters}
In my store/app-logic/getters.js
export default { getAppLogicData: state => state.appLogicData}
Anywhere in the app
computed: { ...mapGetters({ logicData: 'getAppLogicData', coucou: 'getHelloThere' })},mounted () { console.log('coucou', this.coucou) --> salut I am module api console.log('logicData', this.logicData) --> bonjours I am module Logic}
Bonus Point
If you want to communicate between the modules for example a action in app-logic which trigger something in api-logic.So app-logic (module one) to api-logic (module two)
When you specify root: true
it will start to look at the root of the store.
In store/app-logic/actions.js
callPokemonFromAppLogic: ({ dispatch }, id) => { dispatch('callThePokemonFromApiLogic', id, {root:true}); },
In store/api-logic/actions.js
callThePokemonFromApiLogic: ({ commit }, id) => { console.log('I make the call here') axios.get('http://pokeapi.salestock.net/api/v2/pokemon/' + id).then(response => commit('update_pokemon', response.data)) },
In store/api-logic/index.js
add another entry
import actions from './actions';import getters from './getters';import mutations from './mutations';const defaultState = { appLogicData: 'bonjours I am module Logic', pokemon: {}}const inBrowser = typeof window !== 'undefined';// if in browser, use pre-fetched state injected by SSRconst state = (inBrowser && window.__INITIAL_STATE__) ? window.__INITIAL_STATE__.page : defaultState;export default { state, actions, mutations, getters}
In store/api-logic/mutations.js
add the pokemon mutation :p
update_pokemon: (state, pokemon) => { state.pokemon = pokemon }
Anywhere in the app :
computed: { ...mapGetters({ bidule: 'bidule', pokemon: 'getPokemon' })},mounted() { console.log('bidule', this.bidule) this.callPokemonFromAppLogic('1') --> the call console.log('the pokemon', this.pokemon.name) --> 'bulbasaur'},methods: { ...mapActions({ callPokemonFromAppLogic: 'callPokemonFromAppLogic' }),}
At the end your Vue devTool should look like this :)
And Voilà I hope It was clear.Code example :
In nuxt version 2.14^ you don't necessary have to create this in your store root index.js file.
import Vuex from 'vuex';import apiModule from './modules/api-logic';import appModule from './modules/app-logic';const createStore = () => { return new Vuex.Store({ namespaced: true, modules: { appLogic: appModule, api: apiModule } });};export default createStore
But instead, you can just leave your root index.js file as default or do what you need. No need to import.
store/index.js
export const state = () => ({ counter: 0})export const mutations = { increment(state) { state.counter++ }}export const actions = { async nuxtServerInit({ state, commit }, { req }) { const cookies = this.$cookies.getAll() ...}
And this how it looks like, its very simple.
Folder structure
📦store ┣ 📂auth ┣ 📂utils ┣ 📂posts ┃ ┗ 📜actions.js ┃ ┗ 📜mutations.js ┃ ┗ 📜getters.js ┃ ┗ 📜index.js ┣ index.js
Example
store/posts/index.js
you can just put the state function. You don't need to import the actions, getters and mutations.
export const state = () => ({ comments: []})
store/posts/actions.js
const actions = { async getPosts({ commit, state }, obj) { return new Promise((resolve, reject) => { ... } }}export default actions
store/posts/mutations.js
const mutations = { CLEAR_POST_IMAGE_CONTENT: (state) => { state.post_image_content = [] } } export default mutations
store/posts/getters.js
const getters = { datatest: (state) => state.datatest, headlineFeatures: (state) => state.headlineFeatures,}export default getters
The effect is same as @CMarzin answer but much cleaner
Your issue
Use default
exports in your files to achieve the desired effect (no named exports except in the index.js
)
Example
An example can be found directly in the Nuxt.js test suite (at https://github.com/nuxt/nuxt.js/tree/dev/test/fixtures/basic/store/foo).
If you'd run the basic
fixture and access the /store page you'll see the following result
The "repeated" contents in the module itself just show that the split-up values take priority (otherwise getVal
wouldn't return 10 but 99 and state.val
wouldn't be 4 but 2).
store.vue code:
<template> <div> <h1>{{ baz }}</h1> <br> <p>{{ $store.state.counter }}</p> <br> <h2>{{ getVal }}</h2> <br> <h3>{{ getBabVal }}</h3> </div></template><script>import { mapGetters } from 'vuex'export default { computed: { ...mapGetters('foo/bar', ['baz']), ...mapGetters('foo/blarg', ['getVal']), ...mapGetters('bab', ['getBabVal']) }}</script>