In the Nuxt documentation (here) it says 'You can optionally break down a module file into separate files: state.js
, actions.js
, mutations.js
and getters.js
.'
I can't seem to find any examples of how this is done - lots of breaking down the Vuex store at the root level into state.js
, actions.js
, mutations.js
and getters.js
, and into individual module files, but nothing about breaking the modules themselves down.
So currently I have:
├── assets
├── components
└── store
├── moduleOne.js
├── moduleTwo.js
└── etc...
And what I would like to have is:
├── assets
├── components
└── store
└── moduleOne
└── state.js
└── getters.js
└── mutations.js
└── actions.js
└── moduleTwo
└── etc...
To try this out, in /store/moduleOne/state.js
I have:
export const state = () => {
return {
test: 'test'
}
};
and in /store/moduleOne/getters.js
I have:
export const getters = {
getTest (state) {
return state.test;
}
}
In my component I'm accessing this with $store.getters['moduleOne/getters/getTest']
However using the debugger and Vue devtools, it seems like state isn't accessible in the getters file - it seems to be looking for a state in the local file, so state.test
is undefined.
Attempting to import state
from my state.js
file into my getters.js
file doesn't seem to work either.
Does anyone have an example of how they've managed to break the store down like this in Nuxt?
Conclusion. Working with Vuex in a Nuxt application is simple and easy to get started with. It provides module creation based on folder and file structure under the store folder.
In the previous Vuex tutorial, we learned that by default, getters, actions, and mutations inside modules are registered under the global namespace, which allows multiple modules to react to the same mutation or action.
Dynamic module registration makes it possible for other Vue plugins to also leverage Vuex for state management by attaching a module to the application's store. For example, the vuex-router-sync library integrates vue-router with vuex by managing the application's route state in a dynamically attached module.
The Vuex Store comes with Nuxt out of the box but is disabled by default. Creating an index. js file in this directory enables the store. This directory cannot be renamed without extra configuration. Using a store to manage the state is important for every big application.
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 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 SSR
const 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 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 SSR
const 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 SSR
const 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 :
https://github.com/CMarzin/nuxt-vuex-modules
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
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With