Vuex
What is Vuex?
Vuex is a state management pattern developed specifically for Vue.js applications . It uses a centralized storage to manage the state of all components of the application, and uses corresponding rules to ensure that the state changes in a predictable way (reactive change).
What is the "State Management Pattern"?
Let's start with a simple Vue counting app:
new Vue({
// state
data () {
return {
count: 0
}
},
// view
template: `
<div>{
{ count }}</div>
`,
// actions
methods: {
increment () {
this.count++
}
}
})
This stateful self-managing application consists of the following parts:
- state, the data source driving the application;
- view, which declaratively maps state to a view;
- actions, which respond to state changes caused by user input on the view.
The following is a simple representation of the concept of "one-way data flow":
the state data will be displayed on the view, and the user will operate according to the content on the view, thereby triggering actions, and then affecting the state (vue is one-way data flow-driven).
However, the simplicity of unidirectional data flow can easily be broken when our application encounters multiple components sharing state:
- Multiple views depend on the same state.
- Actions from different views need to mutate the same state.
For problem 1, the method of passing parameters will be very cumbersome for multi-layer nested components, and it can't do anything about state transfer between sibling components.
For problem two, we often use parent-child components to directly reference or use events to change and synchronize multiple copies of the state. These patterns above are very brittle and often lead to unmaintainable code.
So, why don't we extract the shared state of the components and manage it in a global singleton mode? In this mode, our component tree constitutes a huge "view", no matter where it is in the tree, any component can get state or trigger behavior!
The following figure extracts the shared state of components and manages them in a global singleton mode.
Application scenarios of Vuex
1. Multiple views depend on the same state (reading), such as token, user information, etc. (data persistence processing is required)
2. Behavior from different views needs to change the same state (write)
Vuex installation
vue2.0 can only install vuex3.x version, up to 3.6.2; vue3.0 can only install vuex4.x version
npm install [email protected] --save
With Vuex installed, let's create a store.
//store/index.js
// 初始化一个vuex的实例(数据仓库) 导出即可
import Vuex from 'vuex'
import Vue from 'vue'
// 使用安装
Vue.use(Vuex)
// 初始化
const store = new Vuex.Store({
// 配置(state|getter|mutations|actions)
state: {
},
getters: {
},
mutations: {
},
actions: {
}
})
export default store
//main.js
+import store from '@/store'
new Vue({
+ store,
render: h => h(App),
}).$mount('#app')
Composition of Vuex
- State: data warehouse;
State itself means data, and it represents the source of data in Vuex. All data in Vuex will be stored in State, which is the only source of data. - Getter: Used to get data;
it can be considered as a computed property of store, just like computed computed property, the return value of getter will be cached according to its dependencies, and will only be recalculated when its dependent value changes . - Mutation: used to modify data;
(1) Mutation is essentially a function.
(2) The operation of Mutation must be synchronous . If it is asynchronous, there will be a lot of trouble. The official explanation is quoted below:
- The main reason why mutation cannot be asynchronous is for debugging , not for not being able to modify the state.
- Action: used to submit mutations, which can perform asynchronous operations.
State
- define data
// 初始化vuex对象
const store = new vuex.Store({
state: {
// 管理数据
count: 0
}
})
- use data
1). Use this directly
<div>A组件 state的数据:{
{
$store.state.count}}</div>
...
created () {
console.log(this.$store.state.count)
}
2). Used in the computed option
computed: {
count () {
return this.$store.state.count
}
}
3). Use mapState auxiliary function
import {
mapState } from vuex
...
computed: {
...mapState(['count'])
// 将一个 state 属性另取一个名字,使用对象形式:
// ...mapState({ newCount: 'count' })
}
...
<div>A组件 state的数据:{
{
count}}</div>
Getter
- Define getters data (understood as computed properties in vuex)
const store = new vuex.Store({
state: {
count: 10
},
// 基于state得到一个新数据
getters: {
newCount (state) {
return state.count++
}
}
})
- use getters data
1). Use this directly
this.$store.getters.newCount
...
<div>{
{
$store.getters.newCount}}</div>
2). Used in computed
<div>{
{
newCount}}</div>
...
computed: {
newCount() {
return this.$store.getters.newCount
}
}
3). Use of mapGetters auxiliary function
import {
mapGetters } from vuex
...
computed: {
...mapGetters(['newCount'])
// 将一个 getter 属性另取一个名字,使用对象形式:
// ...mapGetters({ count: 'newCount' })
},
...
<div>{
{
newCount}}</div>
Mutation
- Define the mutations function
const store = new vuex.Store({
state: {
count: 0
},
mutations: {
// 修改数据的函数
add (state) {
state.count ++
},
// 带参数修改数据的函数
add2 (state, payload) {
// payload 是传参的意思
state.count += payload
}
}
})
- Using the mutations function
1). Use this directly
this.$store.commit('add')
this.$store.commit('add2', 10)
2). The mapMutations auxiliary function is used
import {
mapMutations } from vuex
...
methods: {
...mapMutations(['add','add2'])
// ...mapMutations({ myadd: 'add' })
}
...
<button @click="add">累加1</button>
<button @click="add2(10)">累加10</button>
Action
- Define the actions function
actions: {
// 异步获取数据
getData ({
commit}, payload) {
setTimeout(()=>{
const data = 100
// 通过mutations修改数据
commit('add2', data)
},1000)
}
}
- Use the actions function
1). Use this directly
this.$store.dispatch('getData')
2). mapActions helper function use
import {
mapActions } from vuex
...
methods: {
...mapActions(['getData'])
// ...mapActions({ getMyData: 'getData' })
}
...
<button @click="getData">获取数据</button>
Module
Due to the use of a single state tree, all the state of the application will be concentrated into a relatively large object. When the application becomes very complex, the store object can become quite bloated.
To solve the above problems, Vuex allows us to split the store into modules. Each module has its own state, mutation, action, getter.
When using vuex, if you use module, how to distinguish each module, you need to use namespace
// moduleA模块:
export default {
namespaced:true,
state:{
msg: '我是moduleA中的数据',
num: 0
},
getters:{
msg:state=>state.msg,
num:state=>state.num
},
mutations:{
['ADD_FUN'](state){
return state.num++;
}
},
actions:{
}
};
// moduleB模块:
export default {
namespaced:true,
state:{
msg:'我是moduleB中的msg'
},
getters:{
msg:state=>state.msg
},
mutations:{
},
actions:{
}
};
store/index.js
Register the module in
import Vue from 'vue'
import Vuex from 'vuex'
import moduleA from './moduleA'
import moduleB from './moduleB'
Vue.use(Vuex)
export default new Vuex.Store({
modules:{
// 放每个模块对应的小store
moduleA,
moduleB
}
})
Use module data that adds a namespace
import {
mapGetters, mapMutations } from 'vuex'
export default {
computed: {
...mapGetters('moduleA',['msg','num']),
},
methods: {
...mapMutations('moduleB',['ADD_FUN'])
},
}
- Summary: The use of the vuex module namespace is mainly added
namespaced:true
to each module. When using it,...mapGetters('模块名',['msg'])
you can use it through Tathagata.
Vuex data persistence
The data in vuex will be initialized when the page is refreshed, so it can be introduced vuex-persistedstate
for data persistence. The principle is to store vuex data in localstorage, but the operation process is simplified.
Install vuex-persistedstate
npm install --save vuex-persistedstate
Specific use
import Vue from 'vue'
import Vuex from 'vuex'
import createPersistedState from "vuex-persistedstate"
import moduleA from './moduleA'
Vue.use(Vuex)
const store = new Vuex.Store({
state: {
...},
getters: {
...},
mutations: {
...},
actions: {
...},
modules: {
...},
/* vuex数据持久化配置 */
// 默认会将vuex数据全部持久化
// plugins: [createPersistedState()]
// 按模块引入
createPersistedState({
// 存储方式:localStorage、sessionStorage、cookies
// storage: window.sessionStorage,
// 存储的 key 的key值
// key: "user",
paths: ['moduleA']
})
})
Vuex official website:https://vuex.vuejs.org/zh/installation.html
vuex-persistedstate:https://github.com/robinvdvleuten/vuex-persistedstate