随着对VUE的深度使用,一定会出现多组件嵌套通信、多组件共用同一状态的情况,此时多重嵌套的组件通信就会非常繁琐且兄弟组件的通信是个难以解决的问题,vuex就派上了用场。
在学习vuex之前我先到vue官网上翻看了关于vuex的介绍文档,摘录出一部分做下简单的介绍:
VUE官网将vuex命名为状态管理模式,
Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式。它采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化。
通过在工作中的使用,我简单理解的vuex是一个公共管理组件,它存储着多组件共用的属性和方法,通过这样的方式解决的多嵌套组件状态传递和兄弟组件通信的难题。用后端的角度考虑,vuex抽取封装了一些可复用的属性方法,减少了代码的冗余度。
vuex五大属性
想要使用vuex,必须先了解vuex的核心属性,state、Getters、actions、mutations、modules。在这里我简单介绍一下最常用的也是必选的state、mutations和actions
1、state
以下是vue官网对state的描述
Vuex 使用单一状态树——是的,用一个对象就包含了全部的应用层级状态。至此它便作为一个“唯一数据源 (SSOT)”而存在。这也意味着,每个应用将仅仅包含一个 store 实例。
简单理解,state是vuex的基本数据,用来存放变量,它就相当于定义在单个组件中的data类似。
在VUE组件中想要获取state中定义的属性,可以通过在main.js中引入vuex,通过调用Vue.user(Vuex);将store注入每个子组件,
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
export default new Vuex.Store({
state: {
count: 0;
}
})
const app = new Vue({
el: '#app',
components: { Counter },
template: `
<div class="app">
<counter></counter>
</div>
`
})
子组件中通过this.$store.state.xxx方式获取state中的属性值。
const Counter = {
template: `<div>{{ count }}</div>`,
computed: {
count () {
return this.$store.state.count
}
}
}
通过这样的方式获取store中的state状态非常便捷,但这里有一个问题就是如果我state中有多个状态,且某个组件内部需要获取多个组件,那么就会显得代码非常冗余:
import Vue from 'Vue';
import Vuex from 'Vuex';
Vue.use(Vuex);
export default new Vuex.store({
state: {
count: 1,
msg: '这是一段信息'
}
})
在App.vue 中调用
<template>
<div id="app">
<h1>{{count}}</h1>
<h1>{{msg}}</h1>
</div>
</template>
<script>
export default {
name: 'app',
data() {
return {
}
},
computed:{
count() {
return this.$store.state.count;
},
msg() {
return this.$store.state.msg;
}
}
</script>
相信任何人都不会想重复在computed里面重复写这样的代码多次,vue官方提供了便利的获取多属性方法,辅助函数:mapState,以下是Vue官方示例
import { mapState } from 'vuex'
export default {
// ...
computed: mapState({
// 箭头函数可使代码更简练
count: state => state.count,
// 传字符串参数 'count' 等同于 `state => state.count`
countAlias: 'count',
/* 为了能够使用 `this` 获取局部状态,必须使用常规函数;
可以获取state状态同时再与局部属性进行运算。
*/
countPlusLocalState (state) {
return state.count + this.localCount
}
})
}
通过以上示例,可以明显感受到获取state状态的方法变得简单轻松了。现在我们经常使用的其实是…mapState,通过这样的方法获取state中的状态同时还可以混合其他局部计算属性使用。感兴趣的话可以再去了解一下ES6语法中的对象展开运算符
2、mutaitions
修改状态的唯一方法就是提交mutation,mutations中的方法是同步的。
由于state的使用大体与组件内部的date属性相似,使用state时往往会出现获取state状态后直接修改的场景,这是不被允许的,一般来说对于state中的状态,只有get的权限,不能直接修改,想要修改state就只能通过提交mutation来改变状态。
错误示例:
<template>
<div>
<button @click="addCount"/>
</div>
</template>
<script>
methods: {
addCount() {
this.$store.state.count++;
}
}
</script>
下面通过代码展示正确的修改state属性的方法:
//store.js中
import Vue from 'Vue';
import Vuex from 'Vuex';
Vue.use(Vuex);
export default new Vuex.store({
state: {
count: 1;
},
mutations: {
addNum(state,num) {
return state.count += num;
}
}
})
组件中:
<template>
<div id="app">
<h1>{{count}}</h1>
<button @click="addCount"></button>
</div>
</template>
<script>
export default {
name: 'app',
data () {
return {
}
},
methods: {
addCount () {
//第一个参数是事件的名字,第二个参数是传递的数据
this.$store.commit('addNum', 1)
//对象方式提交
this.$store.commit({
type: 'addNum;,
num: 1
})
}
}
}
</script>
3、actions
actions中可以通过提交mutations来实现异步请求,如果在后台关注一下state就会发现,在mutations中使用异步操作会出现一个问题,就是在实现一个例如延迟一秒给state中的数值属性做运算,页面显示了正常的结果,但是state还保持着计算前的值,这样就会导致别的地方调用这个state属性时候可能出现问题。
使用actions提交mutations来异步操作state状态:
import Vue from 'Vue';
import Vuex from 'Vuex';
Vue.use(Vuex);
export default new Vuex.store({
state: {
count: 1;
},
mutations: {
addNum(state,num) {
return state.count += num;
}
},
actions:{
addCountByasync(context,num) {
setTimeout(()=> {
context.commit('addNum',num)
},1000)
}
}
})