Vue Experience: ⚫️⚫️⚫️⚫️⚪️
Vuex Experience: ⚫️⚫️⚫️⚫️⚫️
Have your ever tried to manage your's application state?
Large applications can often grow in complexity, due to multiple pieces of state scattered across many components and the interactions between them. So, Vue offers Vuex but as official documentation says:
Vuex is using a single state tree, all state of our application is contained inside one big object. However, as our application grows in scale, the store can get really bloated.
To help with that, Vuex allows us to divide our store into modules. Each module can contain its own state, mutations, actions, getters, and even nested modules.
I think you have already got confused, so let's go into code.
# This is a classic store structure with modules
├── index.html
├── main.js
├── components
└── store
├── index.js # where we assemble modules and export the store
└── modules
├── auth.js
├── posts.js
└── comments.js
As you can see we have a store folder with an index.js
and a subfolder named modules
, which contains all modules. But module registration can start to get tedious.
index.js
in store/
import Vue from 'vue'
import Vuex from 'vuex'
import auth from './modules/auth'
import posts from './modules/posts'
import comments from './modules/comments'
// ...
Vue.use(Vuex)
export default new Vuex.Store({
modules: {
auth,
posts,
comments,
// ...
}
})
Example scaffolding for Vuex modules.
export default {
namespaced: true,
state: {},
getters: {},
mutations: {},
actions: {}
}
This is the standard way for registering modules. If you know what namespacing is, go on.
By default, actions, mutations and getters inside modules are still registered under the global namespace - this allows multiple modules to react to the same mutation/action type.
If you want your modules to be more self-contained or reusable, you can mark it as namespaced withnamespaced: true
Let's see Module Registration as mentioned by Chris Fritz(Vue core member) in a VueConf.
🚩 Firstly, let's add a index.js
file in store/modules/
# This is our store structure with modules
├── index.html
├── main.js
├── components
└── store
├── index.js # where we assemble modules and export the store
└── modules
├── index.js # this is the js file that solves the problem
├── auth.js
├── posts.js
└── comments.js
🚩 Then let's modify this index.js
in store/modules/index.js
import camelCase from 'lodash/camelCase'
// Storing in variable a context with all files in this folder
// ending with `.js`.
const requireModule = require.context('.', false, /\.js$/)
const modules = {}
requireModule.keys().forEach(fileName => {
if (fileName === './index.js') return
// filter fullstops and extension
// and return a camel-case name for the file
const moduleName = camelCase(
fileName.replace(/(\.\/|\.js)/g, '')
)
// create a dynamic object with all modules
modules[moduleName] = {
// add namespace here
namespaced: true,
...requireModule(fileName).default
// if you have exported the object with name in the module `js` file
// e.g., export const name = {};
// uncomment this line and comment the above
// ...requireModule(fileName)[moduleName]
}
})
export default modules
🚩 Let's delete namespacing from every module js file.
// export const name = { if you want to export an object with name
export default {
// namespaced: true, delete this line
state: {},
getters: {},
mutations: {},
actions: {}
}
🚩 Finally the code from above, where we had to import all the modules can change to:
index.js
in store/
import Vue from 'vue'
import Vuex from 'vuex'
import modules from './modules'
Vue.use(Vuex)
export default new Vuex.Store({
modules
})
I think we have done an ''automated'' system that includes every file in modules folder. A smarter and cleaner code.
Until next time...Happy coding!
Top comments (9)
Hi!
I've also watched this video and inspired by the parts about auto registration for vuex modules and components. I've tried these techniques in my workflow, but I've found that they are less flexible than manual imports.
For example: I want to add
axios
hook for401
response code and unauthorize the user in this case. If I have auto-module-registration, I have to define this hook somewhere outside the store. I think it's better to define this hook in the module definition, by exporting vuex plugin function from module and then register this plugin in store index file. Something like this:in conclusion I think that you described a good technique and it's great for boilerplates and fast prototyping, but it's not a very flexible
I agree with you.
Of course, you need a good experience with Vuex. In your example,
auth.js
module file has different workflow from standard modules.Every project is different. As you said above, this technique make your development faster and (cleaner), but loses a little bit from flexibility. Before designing the architecture of a project's store, you have to consider the pros and cons of this auto-registration pattern and if it suits to your project.
Hey,
I've also tried this autoloader. There is one problem I found. When I want to start my tests (tests for modules in vuex), the jest fails on: TypeError: require.context is not a function. Does anybody has solution for this?
Hi, thank you for the post.
I have a question if you can help me.
I have the following folder structure in my project
project
|
-store
|
|-constants.js
|-modules
|
|-someModule
|-otherModule
|-index.js (just as in your post)
This is a sample from my constants file
//Actions
export const USER_SET = 'user/SET'
export const USER_GET_ROLES = 'user/GET_ROLES'
//Mutations
export const USER_SET_BY_KEY = 'user/SET_BY_KEY'
export const USER_SET_ROLES = 'user/SET_ROLES'
And in my modules I use the constant as name for the actions, mutations, getters, like in this sample
const actions =
{
[constants.USER_SET]: ({commit}, user) =>
{
let response = {'data': user, 'key': 'user' }
commit(constants.USER_SET_BY_KEY, response)
},
}
The idea is that when I use in components, i use the constants file name too, this way I can change the name in one place
Like in this
...mapActions({
getRoles: constants.USER_GET_ROLES,
The thing is, even when the module are dinamically loaded by the index in the modules folder, Vuex doesn't recognize the actions, mutations, getters
I print the modules object in the index and i see that it has this properties empty
{
"customer": {
"state": {
"customers": null,
"contacts": null
},
"actions": {},
"mutations": {},
"getters": {}
},
.
.
.
.
}
If I go back to import every module manually and put then in the vuex individually, then vuex recognize the actions, mutations, getters
So thank you in advance if can you please point me in the right direction
p.s Sorry for my bad english, it's not my native language
Nevermind, It was a problem with the way I was telling vuex to use modules but thank you anyway
okay but how to use it after we do that for example i used to do this :
context.commit('products/decrementProductInventory', product, {root: true})
how i am gonna use it now ?
Very interesting!
Would you like to do the same with router modules?
My unit tests are failing because jest can't figure out what
require.context
is 🤦Some comments may only be visible to logged-in visitors. Sign in to view all comments. Some comments have been hidden by the post's author - find out more