Official Definition#
Vuex is a state management pattern designed for Vue.js applications. It adopts a centralized storage to manage the state of all components in the application and ensures that the state changes in a predictable manner according to corresponding rules.
Injecting Vuex#
import store from "./store";
new Vue({
store,
});
store.js
import Vue from "vue";
import Vuex from "vuex";
Vue.use(Vuex);
export default new Vuex.Store({
state: {
msg: "hello world",
},
mutations: {},
actions: {},
});
Accessing State#
In any component, you can access the msg
like this:
<template>
<div class="about">
<h1>This is an about page</h1>
<h2>{{$store.state.msg}}</h2>
</div>
</template>
Modifying State#
Let mutations
provide a method to modify the state:
mutations: {
setMsg(state, newMsg) {
state.msg = newMsg
}
}
Then let actions
submit the modification request:
actions: {
setMsg ({ commit }) {
commit('setMsg', 'hello')
}
}
Trigger the modification action in other components:
<template>
<div class="about">
<h1>This is an about page</h1>
<h2>{{$store.state.msg}}</h2>
</div>
</template>
<script>
export default {
mounted () {
this.$store.dispatch('setMsg')
}
}
</script>
Considerations#
The above example is a simple state management. state
stores the state, mutations
provides methods to modify the state, and actions
is responsible for triggering the methods to modify the state and submitting the modified data. In the example, the data modified in actions
is done manually, but in actual work, it should be the data submitted by the request. However, there is an obvious problem in the example, anyone can modify (dispatch
) the state.
Namespaces#
If the project is complex enough, you can use the namespace provided by Vuex to modify the state. To use namespaces, you need to use modules
in addition to vuex
. modules
is an object, and its structure also consists of state
, mutations
, and actions
. The difference is that it has an additional namespaced
property to use namespaces.
Three Methods to Modify State#
Dispatch#
First, extract the original content into a modules
:
store.js
import Vue from "vue";
import Vuex from "vuex";
import home from "./modules/home";
Vue.use(Vuex);
export default new Vuex.Store({
modules: {
home,
},
});
./modules/home.js
export default {
namespaced: true,
state: {
msg: "hello world",
},
actions: {
setMsg({ commit }) {
commit("setMsg", "hello");
},
},
mutations: {
setMsg(state, newMsg) {
state.msg = newMsg;
},
},
};
Finally, retrieve and modify the state:
<template>
<div class="about">
<h1>This is an about page</h1>
<h2>{{$store.state.home.msg}}</h2>
</div>
</template>
<script>
export default {
mounted () {
this.$store.dispatch('home/setMsg')
}
}
</script>
Observe the difference between the final modification and the previous one. The only difference is that there is an additional home
when retrieving and modifying the state, which increases the usage threshold. However, at least it can identify which module's state is being operated on.
There is another equivalent way to modify the state through modules
:
mapActions#
<template>
<div class="about">
<h1>This is an about page</h1>
<h2>{{$store.state.home.msg}}</h2>
</div>
</template>
<script>
import { mapActions } from 'vuex'
export default {
methods: {
...mapActions('home', ['setMsg'])
},
mounted () {
this.setMsg()
}
}
</script>
After executing mapActions
, it returns an object. After spreading it, a setMsg
method will be added to the current instance. Calling this method will trigger the modification of the state.
createNamespacedHelpers#
Both of the above methods have an obvious problem. If there are many states that need to be modified in the current component, it means that there will be many layers of home
. By using createNamespacedHelpers
provided by Vuex, this problem can be solved in a friendly way.
<template>
<div class='about'>
<h1>This is an about page</h1>
<h2>{{$store.state.home.msg}}</h2>
</div>
</template>
<script>
import { createNamespacedHelpers } from 'vuex'
const { mapActions } = createNamespacedHelpers('home')
export default {
methods: {
...mapActions(['setMsg'])
},
mounted () {
this.setMsg()
}
}
</script>
Simplify Value Retrieval#
The previous examples did not mention the issue of value retrieval, and it is not recommended to do so in actual work. Vuex provides a mapState
method to simplify value retrieval.
<template>
<div class='about'>
<h1>This is an about page</h1>
<h2>{{msg}}</h2>
</div>
</template>
<script>
import { createNamespacedHelpers } from 'vuex'
const { mapActions, mapState } = createNamespacedHelpers('home')
export default {
computed: {
...mapState(['msg'])
},
methods: {
...mapActions(['setMsg'])
},
mounted () {
this.setMsg()
}
}
</script>
Extract Variables#
Recall how many times the word setMsg
appeared. It appeared in the component, in the store
or modules
. At this time, it is advocated to extract this setMsg
into a constant to be saved. This makes it easier for oneself or others to maintain.
./store/action-type.js
export const SET_MSG = "setMsg";
When using it, try to avoid using setMsg
directly. This makes it easier for yourself or others to maintain.
Summary#
The convenience of Vuex is self-evident. According to the complexity of the project, it provides a progressive enhancement solution. When the project is simple, basic requirements can be met without using modules
. If the complexity increases, modules
is the best choice. If there are not many modules, you can simply use dispatch
. Even if there are many modules, createNamespacedHelpers
has paved the way for subsequent work.