We already know Vuex from this tutorial. In fact, with it, you can manage all your data (the state) from a single place: the store. While this sounds good, it comes with a drawback: your store can become messy. After all, the store is the file that contains all the data your application is working on. This is not really what we want in order to have maintainable code. As we will see in this Vuex Modules Tutorial, modules are an elegant way to solve this problem by dividing your store into different files.
Vuex Modules Tutorial
Introducing Modules
Vuex Modules are simply Vuex stores inside other Vuex stores. Don’t worry, it is much simpler than it sounds. In our previous tutorial, we created a store with mutations, getters, and actions. Well, you can also create a store by including one or more modules in it. Before we do that, we will see in this Vuex modules tutorial on how to create a module.
Since a Vuex store can have multiple module, we recommend creating a folder named /store
in your project. In it, create index.js
to write the store itself, and one js
file for each store module you need. In our example, we will have only one module, but you can have more than one.
A module is just a store, and you write it exactly like a store, except you don’t use Vuex.Store
. Instead, you define it as a normal object. Take a look at the example below, a simple authentication store. You can save the code below in /store/auth.js
.
import axios from 'axios'
const auth = {
state: {
userdata: null
},
mutations: {
login (state, payload) {
state.userdata = payload
},
logout (state) {
state.userdata = null
}
},
actions: {
authenticate ({ commit }, { username, password }) {
axios({
method: 'post',
url: '/my/backend/url',
data: {
username: username,
password: password
}
})
.then(response => {
if (response.status === 200) {
commit('login', response.data)
}
}
},
getters: {
loggedIn. function (state) {
return state.userdata !== null
}
}
}
export default auth
Including modules in the Store
Now the next part of our Vuex Modules tutorial: including a module in the store. Including a module is as simple as defining the modules attribute. Your Vuex Store will look something like this:
import Vue from 'vue'
import Vuex from 'vuex'
import auth from './auth'
Vue.use(Vuex)
export default new Vuex.Store({
modules: {
auth,
// other modules here ...
}
})
And this is it! Now, we only need to know how to call actions, mutations, and getters of our module from our application.
By default, modules are not namespaced. This means that all the properties of the module will be reflected directly in the store. This means that our store will have the mutation login
, even if we defined it in the auth
module. We can access it from any Vue component like below.
// State
this.$store.state.userdata
// Mutation
this.$store.commit('login', { username: 'logged_user' })
// Action
this.$store.dispatch('authenticate', { username: this.username, password: this.password })
// Getter
this.$store.getters.loggedIn
Of course, using modules in this way reduces the complexity when writing the store, but not when using it.
Namespacing Vuex Modules
The next frontier of our Vuex Modules Tutorial is namespacing our modules. Namespacing a module simply means it won’t inject its properties in the store directly. Instead, to access them, we need to reference it in a tree-like structure. This approach requires a little bit more code but is way more scalable and maintainable. To define that your module will be namespaced, simply set the namespace
property to true.
import axios from 'axios'
const auth = {
namespaced: true,
// State, mutations, actions, getters ...
}
export default auth
You don’t even need to change the code in your store index. That’s all you need to do on the module side. Instead, you need to do something when referencing the module properties. In fact, they are not on the root of the store anymore. To reference them, you need to call them with a path-like naming convention. This naming convention uses the module name and the property name, separated by a slash.
// State
this.$store.state.auth.userdata
// Mutation
this.$store.commit('auth/login', { username: 'logged_user' })
// Action
this.$store.dispatch('auth/authenticate', { username: this.username, password: this.password })
// Getter
this.$store.getters['auth/loggedIn']
You can also nest multiple modules with the same naming convention: module/nestedModule/login
. Furthermore, you can mix namespaced modules with non-namespaced modules. Imagine that nestedModule
is not namespaced but module
is, the login property in nestedModule
will be accessed with module/login
.
Renaming modules
You can also rename modules when you include them in the modules
section. Instead of listing them as we did before, provide a key:
import Vue from 'vue'
import Vuex from 'vuex'
import auth from './auth'
Vue.use(Vuex)
export default new Vuex.Store({
modules: {
authentication: auth,
// other modules here ...
}
})
In this case, we will reference our module with authentication
, not with auth
. That’s because authentication is its name inside this store.
In Conclusion
In this Vuex Modules Tutorial, we saw how to make your store modular. Each module is basically a store, with all its properties: mutations, actions, getters, and so on. Once you have a module, you can import them in a store or in another module by referencing it inside the modules
property. Furthermore, namespacing modules allow you to access the properties in a tree-like structure and avoid conflicts. In case you want to dive deeper into Vuex Modules, you can always take a look at the official docs.
What do you think of Vuex modules? Do you use them to better structure your application? Let me know your opinions in the comments!