首先什么是vuex,官网的解释是状态管理模式、集中式存储管理
###什么是状态管理模式:
状态即决定视图表现的数据,比如我们会在组件的data
中定义一个numbe:1
,那么我们就可以在组件中显示该数据,在Vuex中就被称为状态。一个组件中会定义很多个状态,这个时候就需要分类管理了,比如一个班级下面会有人数,性别等状态,如果把班级当作一个文件夹,那个人数,性别等状态就是该文件夹下面的文件,就出现了层级关系,这个就是状态树
。
###什么是集中式存储管理:
集中即代表不是分散的,不是各个组件单独维护自己的状态(在组件中使用 data配置项声明),而是集中管理,可以理解为一种响应式的全局变量,准确来说是要求应用建立并维护一个单一的、全应用范围共享的状态树
###什么时候要用到vuex:
vue里面是由一个又一个组件组成的,所以就存在组件中的通信,组件的通信有很多方法,但是如果不是简单的父子组件的通信,而是一个状态需要共享给多个组件时,就会非常麻烦,数据也会相当难维护
###什么是状态库:
Vuex的Store类 —— 状态库 —— 用于管理状态树,它的实例化配置项state 用来声明要创建的状态树,代码如下:
const store = new Vuex.Store({
state:{ numner:0 }//state:存储状态。也就是变量
})
###如何使用状态库:
为了避免每个组件都要引入,我们可以在vue实例化的时候将状态库挂接为Vue实例的一个属性上
new Vue({
store:store, //使用store配置项,就可以将状态库挂接为Vue实例 的属性$store
template:'<ez-counter/>',
components:{EzCounter}
})
###如何访问state里面的状态:
使用计算属性
computed: {
number () {
return this.$store.state.number
}
},
引入辅助函数mapState
//这里的state => state.number是es6里面的箭头函数相当于
//function(state) {
// return state.number
//}
import { mapState } from 'vuex';
export default {
computed: {
...mapState({
number : state => state.number ,
number 1: state => state.number1
})
},
如果state里面定义的字段和页面要显示的字段是一样的话,也可以写成数组模式
...mapState([
'number ',
'number 1'
])
###什么时候使用getter:
getter:官方的解释是可复用的计算属性 —— 派生状态,说明白了也就是对state里面状态的进一步操作,比如数组的排序,过滤等,当多个组件需要这个功能的时候可以进行复用,可以理解为一个全局的公用函数,官方的例子如下:
const store = new Vuex.Store({
state: {
todos: [
{ id: 1, text: '...', done: true },
{ id: 2, text: '...', done: false }
]
},
//对列表进行过滤
getters: {
doneTodos: state => {
return state.todos.filter(todo => todo.done)
}
},
//Getter 也可以接受其他 getter 作为第二个参数:用来调用其他的getter
doneTodosCount: (state, getters) => {
return getters.doneTodos.length
}
})
引入辅助函数mapGetters,方法和mapState一样,讲上面的mapState改成mapGetters就可以了
###什么是严格模式:
在严格模式下,无论何时发生了状态变更且不是由 mutation 函数引起的,将会抛出错误。这能保证所有的状态变更都能被调试工具跟踪到。
开启严格模式,仅需在创建 store 的时候传入 strict: true
:
const store = new Vuex.Store({
// ...
strict: true
})
###什么是状态变更管理
Vuex要求组件将状态树视为只读,组件不应该直接修改状态树上的状态, 而是通过提申请的方式,由状态库来实际执行状态变更的操作:
在严格模式下,Vuex的状态约定为只读的,因此我们只能将其单向映射 为组件的只读计算属性,更改 Vuex 的 store 中的状态的唯一方法是提交 mutation
const store = new Vuex.Store({
state:{number:0},
mutations:{
INCREASE(state,payload){ state.number= payload.num}
}
})
这里可以传两个参数一个是state,另一个是提交的时候传过来的参数,可以是个字符串,也可以是个对象,如果这里需要接收多个参数,只能以对象的形式传,mutations里面的函数没有第三个参数,提交代码如下:
this.$store.commit('INCREASE', {
num: 10
});
//也可以这样传,type为函数名,其他的都是传参
this.$store.commit({
type: 'INCREASE',
num: 10
})
这里可以使用 mapMutations 辅助函数,和之前的state,getter差不多,代码如下
import { mapMutations } from 'vuex'
export default {
// ...
methods: {
//名字一样时可以用数组的形式
...mapMutations([
'INCREASE'
// `mapMutations` 也支持载荷:
'INCREASE' // 将 `this.INCREASE(amount)` 映射为 `this.$store.commit('INCREASE', amount)`
]),
...mapMutations({
add: 'INCREASE' // 也可以设置成想要的函数名称
})
}
}
然而mutation是同步的,不能写异步代码
###为什么要保证状态变更的同步性
Vuex作为一个状态管理系统,其核心特性就在于保证每一个状态变更(mutation)的 可跟踪性,异步代码会导致状态变更与应用状态的不一致,因而导致了应用状态的不可预测性。
我们在RESET变更处理器中加入了异步代码:
const store = new Vuex.Store({
state:{ number:0},
mutations:{
reset: state => setTimeout(() => state.number= 0, 3000)
}
})
当事件触发是状态counter被重置为0,
但现在的问题是当点击按钮的同时couter状态并没有马上变化,而是3秒钟后异步代码执行后才发生改变,这就导致不可预测,这个时候就引入了action
###如何使用action
const store = new Vuex.Store({
state:{number:0},
mutations:{
INCREASE(state,payload){ state.number= payload.num}
},
actions:{
//写法一
add(context) {
context.commit('INCREASE')
}
//写法二
add({ commit }) {
commit('INCREASE')
}
})
// 这里用到了对象的结构
//因为函数的参数是一个对象,函数中用的是对象中一个方法,我们可以通过对象的
//解构赋值直接获取到该方法
//因为context本身就是一个对象,里面有state对象和commit方法例如
let context {
state: {},
commit: function(){}
}
//根据对象结构可以定义如下:
let {state,commit} = context
console.log(state)//state: {};
console.log(commit)//commit: function(){};
//所以放在函数里面就是
add({state,commit} ) {
commit('INCREASE')
}
调用this.$store.dispatch(‘add’)
###如何使用Module
由于将整个应用的状态保存在单一的状态树中,对于复杂的应用而言, 这个状态树将相当的大。因此,Vuex允许我们将状态树拆分为状态管理模块(module)
例如,下面定义了两个状态模块modCounter和modClock:
const add= {
state:{number:0},
mutations:{ INCREASE(state){state.number++} }
}
const add1 = {
state:{number1:0},
mutations:{ADD(state,val){state.time = val}}
}
const store = new Vuex.Store({
modules:{
a1:add,
a2: add1
}
})
访问模块的状态
//访问a1模块的number1状态,
console.log(this.$store.state.a1.number1)
//访问a2模块的number2状态。
console.log(this.$store.state.a2.number2)