一、什么是vuex
Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式
二、什么是状态管理
先了解下单向数据流 帮助我们更好地理解状态管理。平时我们写的简单vue文件中,包含data,template,methods这三个部分可以分别把data看作 state,驱动应用的数据源,也就是定义的变量;
template 看作 view 以声明方式将 state 映射到视图, 显示变量;
methods 看作 actions,响应在 view 上的状态变化;
三、为什么要用vuex
如果我们遇到多个视图依赖于同一状态和来自不同视图的行为需要变更同一状态,这种单向数据流虽然也能通过组件兄弟/父子通信传值来实现,但是代码会变得复杂不好维护。因此:
1.把组件的共享状态抽取出来,以一个全局单例模式管理
在这种模式下,我们的组件树构成了一个巨大的“视图”,不管在树的哪个位置,任何组件都能获取状态或者触发行为(这句话的意思简单理解: vuex把项目里共享状态一般会把抽离出来放在store文件夹中,这时项目中所有的vue文件template都是视图,而store中的状态可以通过this.$store.去获取你定义的状态,能做到不管哪个vue文件都能获取到,也都能变更和触发store的行为)
2.通过定义和隔离状态管理中的各种概念并通过强制规则维持视图和状态间的独立性,我们的代码将会变得更结构化且易维护(这句话不好理解就简单理解成: vuex中定义了state, getters, mutations, actions四个属性,不同的属性做不同的事情就是用来维护状态,视图,行为的独立性)
简单来说,vuex 就是使用一个 store 对象来包含所有的应用层级状态,也就是数据的来源。当然如果应用比较庞大,我们可以将store模块化,也就是每个模块都有自己的 store。
四、初步理解vuex中state,getter,mutation,action
state:定义变量;
getters:获取变量;
mutations:同步执行对变量进行的操作;
actions:异步执行对变量进行的操作;
vuex中的mapState,mapGetters,mapActions,mapMutations均是辅助函数。
五、如何使用vuex中state,getter,mutation,action
1、mapState
引入vuex 以后,我们需要在state中定义变量,类似于vue中的data,通过state来存放状态。
比如我们在vuex中定义state为:
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex);
export default new Vuex.Store({
state: {//存放状态,类似于data
nickname:'qiqi',
age:18,
gender:'女',
firstname:'浮',
lastname:'游',
days:1000,
},
getters:{},
mutations: {},
actions: {},
modules: {}
})
我们想在组件中使用nickname,age,gender这三个属性。props,methods,data和computed的初始化都是在beforeCreated和created之间完成的,所以我们在computed中使用属性。
当我们不使用mapState时,store 实例会注入到根组件下的所有子组件中,且子组件能通过 this.$store 访问到。代码如下:
<template>
<div>
<h1>昵称为:{{nickname}}</h1>
<h1>{{nickname}}年龄是:{{age}}</h1>
<h1>性别是:{{gender}}</h1>
</div>
</template>
<script>
export default {
name: "Vhome",
computed:{
nickname(){
return this.$store.state.nickname;
},
age(){
return this.$store.state.age;
},
gender(){
return this.$store.state.gender;
}
},
}
</script>
当一个组件需要获取多个状态的时候,将这些状态都声明为计算属性会有些重复和冗余。为了解决这个问题,我们可以使用 mapState 辅助函数帮助我们生成计算属性:
import {mapState} from 'vuex'
export default {
name: "Vhome",
computed:{
...mapState(['nickname','age','gender']),
// nickname(){
// return this.$store.state.nickname;
// },
// age(){
// return this.$store.state.age;
// },
// gender(){
// return this.$store.state.gender;
// }
},
}
记住:用mapState等这种辅助函数的时候,前面的方法名和获取的属性名是一致的。
2、mapGetters
vuex 允许我们在 store 中定义“getter”(可以认为是 store 的计算属性)。就像计算属性一样,getter 的返回值会根据它的依赖被缓存起来,且只有当它的依赖值发生了改变才会被重新计算。vuex部分代码如下所示:
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex);
export default new Vuex.Store({
state: {//存放状态,类似于data
nickname:'qiqi',
age:18,
gender:'女',
firstname:'浮',
lastname:'游',
days:1000,
},
getters:{
realname(state){
return state.firstname+state.lastname
},
days_us(state){
return (state.days/7).toFixed(2)
}
},
mutations: {},
actions: {},
modules: {}
})
HTML部分为:
<h1>全名为:{{realname}}</h1>
<h1>周数为:{{days_us}}</h1>
不使用mapGetters时,js部分为:
computed:{
realname(){
return this.$store.getters.realname;
},
days_us(){
return this.$store.getters.days_us;
},
},
当使用mapGetters时,js部分为:
import {mapGetters} from 'vuex'
export default {
name: "Vhome",
computed:{
// realname(){
// return this.$store.getters.realname;
// },
// days_us(){
// return this.$store.getters.days_us;
// },
...mapGetters(['realname','days_us']),
},
}
3、mapMutations
更改 vuex 的 store 中的状态的唯一方法是提交 mutation。
vuex 中的 mutation 非常类似于事件:每个 mutation 都有一个字符串的事件类型 (type) 和 一个 回调函数 (handler)。这个回调函数就是我们实际进行状态更改的地方,并且它会接受 state 作为第一个参数。
例如我们实现点击按钮年龄加1的需求,vuex代码如下:
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex);
export default new Vuex.Store({
state: {//存放状态,类似于data
nickname:'qiqi',
age:18,
gender:'女',
firstname:'浮',
lastname:'游',
days:1000,
},
getters:{
realname(state){
return state.firstname+state.lastname
},
days_us(state){
return (state.days/7).toFixed(2)
}
},
mutations: {//类似于methods
addAge(state){
state.age++;
}
},
actions: {},
modules: {}
})
当不使用mapMutations时,使用 this.$store.commit(‘xxx’) 提交 mutation。HTML代码部分如下:
<div><button @click="test">使用mutations年龄加1</button></div>
js代码如下:
methods:{
test(){
this.$store.commit('addAge')
},
}
当使用mapMutations时,将组件中的 methods 映射为 store.commit 调用。HTML代码部分如下:
<div><button @click="addAge">使用mutations年龄加1</button></div>
js代码如下:
import {mapMutations} from 'vuex'
export default {
name: "Vhome",
methods:{
// test(){
// this.$store.commit('addAge')
// },
...mapMutations(['addAge']),
}
}
记住:mutation 必须是同步函数
4、mapActions
Action 类似于 mutation,不同在于:
Action 提交的是 mutation,而不是直接变更状态。
Action 可以包含任意异步操作。
例如我们需要操作年龄,vuex代码如下:
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex);
export default new Vuex.Store({
state: {//存放状态,类似于data
nickname:'qiqi',
age:18,
gender:'女',
firstname:'浮',
lastname:'游',
days:1000,
},
getters:{
realname(state){
return state.firstname+state.lastname
},
days_us(state){
return (state.days/7).toFixed(2)
}
},
mutations: {//类似于methods
addAge(state){
state.age++;
}
},
actions: {
addAgeAction({ commit }){
commit('addAge');
}
},
modules: {}
})
不使用mapActions时,Action 通过 store.dispatch 方法触发。HTML代码如下:
<div><button @click="test1">使用actions使年龄加1</button></div>
js代码如下:
methods:{
test1(){
this.$store.dispatch('addAgeAction')
}
}
使用mapActions时,将组件的 methods 映射为 store.dispatch 调用。HTML代码如下:
<div><button @click="addAgeAction">使用actions使年龄加1</button></div>
js代码如下:
import {mapActions} from 'vuex'
export default {
name: "Vhome",
methods:{
...mapActions(['addAgeAction']),
}
}
mutation 必须同步执行,Action 就不受约束!我们可以在 action 内部执行异步操作。