Vuex is a state management pattern + library
Vuex is a state management pattern + library for Vue.js applications. It serves as a centralized store for all the components in an application, with rules ensuring that the state can only be mutated in a predictable fashion. It also integrates with Vue's official devtools extension to provide advanced features such as zero-config time-travel debugging and state snapshot export / import.
Vue.js is an easy to use web app framework that we can use to develop interactive front end apps. With Vuex, we can store our Vue app’s state in a central location. In this article, we’ll look at how to add modules to separate a Vuex store into smaller parts.
Dividing a Store into Modules
Vuex uses a single state tree. This means the states are located in one big object
. This will be bloated is our app grows big.
To make a Vuex store easier to scale, it can be separated into modules
. Each module can have its own state, mutations, getters, and actions
.
The state parameter in mutations and getters are the module’s local state
.
By default, all actions, mutations, and getters inside modules are registered under a global namespace. This allows multiple modules to react to the same mutation or action type.
We can divide our store into module as in the following example:
const moduleA = {
state: {
count: 0
},
mutations: {
increase(state, payload) {
state.count += payload.amount;
}
},
actions: {
increase({ commit }, payload) {
commit("increase", payload);
}
}
};
const moduleB = {
state: {
count: 1
},
mutations: {
increase(state, payload) {
state.count += payload.amount;
}
},
actions: {
increase({ commit }, payload) {
commit("increase", payload);
}
}
};
const store = new Vuex.Store({
modules: {
a: moduleA,
b: moduleB
}
});
console.log(store.state.a.count);
console.log(store.state.b.count);
Then in the console.log output, we should see 0 and 1 since moduleA ‘s initial count state is 0 and moduleB ‘s initial count state is 1.
To make each module self-contained
, we have to namespace it by setting the namespaced option to true
.
We can namespace a module and then call dispatch on actions after namespacing the modules as follows:
const moduleA = {
namespaced: true,
state: {
count: 0
},
mutations: {
increase(state, payload) {
state.count += payload.amount;
}
},
actions: {
increase({ commit }, payload) {
commit("increase", payload);
}
}
};
const moduleB = {
namespaced: true,
state: {
count: 1
},
mutations: {
increase(state, payload) {
state.count += payload.amount;
}
},
actions: {
increase({ commit }, payload) {
commit("increase", payload);
}
}
};
const store = new Vuex.Store({
modules: {
a: moduleA,
b: moduleB
}
});
new Vue({
el: "#app",
store,
computed: {
...Vuex.mapState({
a: state => state.a,
b: state => state.b
})
},
methods: {
increaseA(payload) {
this.$store.dispatch("a/increase", payload);
},
increaseB(payload) {
this.$store.dispatch("b/increase", payload);
}
}
});
<body>
<div id="app">
<button @click="increaseA({amount: 10})">Increase</button>
<button @click="increaseB({amount: 10})">Increase</button>
<p>A Count: {{a.count}}</p>
<p>B Count: {{b.count}}</p>
</div>
<script src="index.js"></script>
</body>
In the code above, we have namespaced: true set in each module, and then we added 2 methods to our Vue instance to dispatch the namespaced actions:
increaseA(payload) {
this.$store.dispatch("a/increase", payload);
}
and:
increaseB(payload) {
this.$store.dispatch("b/increase", payload);
}
Since we have namespaced set to true , we have to dispatch the actions by passing in “a/increase” and “b/increase” to dispatch .
Dynamic Module Registration
We can also register a module dynamically by using the store.registerModule method as follows: index.js :
const moduleA = {
state: {
count: 0
},
mutations: {
increase(state, payload) {
state.count += payload.amount;
}
},
actions: {
increase({ commit }, payload) {
commit("increase", payload);
}
}
};
const store = new Vuex.Store({});
store.registerModule("a", moduleA);
new Vue({
el: "#app",
store,
computed: {
...Vuex.mapState({
a: state => state.a
})
},
methods: {
...Vuex.mapActions(["increase"])
}
});
index.html :
<!DOCTYPE html>
<html>
<head>
<title>App</title>
<meta charset="UTF-8" />
<script src="https://unpkg.com/vue/dist/vue.js"></script>
<script src="https://unpkg.com/vuex"></script>
</head>
<body>
<div id="app">
<button @click="increase({amount: 10})">Increase</button>
<p>A Count: {{a.count}}</p>
</div>
<script src="index.js"></script>
</body>
</html>
Conclusion
If our Vuex store is big, we can divide it into modules.
We can register modules when we create the store or dynamically with registerModule
.
Then we can map actions/mutations
by their name as usual, and we can map the state by accessing state.a.count
, where a is the module name, and count is the state name. Replace it with our own module and state names if the code is different.
Comments