在进入vuex之前,先看一看一个简单的关于计数器的例子,通过这个例子大概过一遍vuex的基本功能:
在Vue实例的created钩子中,应用启动了一个定时器,用来周期性地 递增counter
属性的值 —— 由于counter
是响应式属性,它的变化因而 驱动了视图随之刷新。像counter这样可以决定 视图表现的数据,在Vuex中就被称为状态。
计数器应用相当简单,因此我们只需要定义一个状态就可以了。稍微复杂 一些的应用,则可能需要我们抽象出成百上千的状态,这时候就需要分类 管理了。就还比上图,应用的全部状态,构成了一棵层级分明的状态树。而Vuex的作用 ,就在于管理一个应用的状态树
应用单一状态树
Vuex进行应用状态管理的第一个手段,是要求应用建立并维护一个单一的、全 应用范围共享的状态树,而不是各个组件单独维护自己的状态(在组件中使用 data配置项声明)
Vuex的Store类就是一个状态库 ,用于管理状态树,它的实例化配置项state 用来声明要创建的状态树。例如,下面的代码创建了一个包含状态counter的 状态库:
const store = new Vuex.Store({
state:{ counter:0 }
})
利用状态库的state属性,就可以访问到其管理的状态树了。例如,通过 store.state.counter来访问counter状态。
将状态库注入组件,是将状态库挂接为Vue实例的一个属性上,这样我们就可以在模板中 直接访问状态树了
在创建Vue实例时,使用store配置项,就可以将状态库挂接为Vue实例 的属性$store
例如,下面的代码使用store配置项,将状态库store注入根组件,因此 我们可以在EzCounter组件中利用$store属性访问状态库:
const EzCounter = {
template:'<div class="counter">{{$store.state.counter}}</div>'
}
new Vue({
store:store,
template:'<ez-counter/>',
components:{EzCounter}
})
状态变更管理
Vuex要求组件将状态树视为只读,组件不应该直接修改状态树上的状态, 而是通过提申请的方式,由状态库来实际执行状态变更的操作:
对于计数器应用来讲,修改counter状态的需求有两个:递增和复位。 因此,我们需要首先在状态库中声明两个变更处理器(mutation handler)。
在创建状态库时,使用mutations配置项来声明变更处理器。例如,下面 的代码为状态库声明了两个变更处理器:INCREASE和RESET:
const store = new Vuex.Store({
state:{counter:0},
mutations:{
INCREASE: state => state.counter++ ,
RESET: state => state.counter = 0
}
})
在组件中的使用方法:
methods:{
inc() { this.$store.commit('INCREASE') }
},
状态变更的同步性
Vuex要求应用保证状态变更(mutation)的 同步性 —— 状态变更处理器执行完之时,状态更新一定要完成。
这意味着,在状态变更处理器里不能执行异步代码。这一要求直接导致了新的 环节的引入 —— 状态动作(action):
在创建状态库时,使用actions配置项声明状态动作。例如,下面的代码 声明了两个状态动作inc和reset,分别用来提交INCREASE和RESET变更 请求:
const store = new Vuex.Store({
state:{counter:0},
mutations:{
INCREASE:state => state.counter++,
RESET: state => state.counter = 0
},
actions:{
inc: context => context.commit('INCREASE'),
reset: context => context.commit('RESET')
}
})
context参数是一个局部上下文对象, 我们已经知道它是Vuex为模块构造的状态库局部镜像,因此调用它的commit()方法, 就可以提交变更请求了。
调用状态库的dispatch()方法来分发执行指定名称的状态动作。例如, 下面的代码要求状态库执行inc动作:
this.$store.dispatch('inc')
为什么要保证状态变更的同步性
Vuex作为一个状态管理系统,其核心特性就在于保证每一个状态变更(mutation)的 可跟踪性,这就是为什么状态变更处理器(mutation handler)必须是同步的,同步性的状态变更的意义,就在于每一个变更执行完成后都可以对应到一 个新的状态
假如,状态变更(mutation)是异步的,会怎么样?
这会导致状态变更与应用状态的不一致,因而导致了应用状态的不可预测性。
我们在RESET变更处理器中加入了异步代码:
const store = new Vuex.Store({
state:{ counter:0},
mutations:{
RESET: state => setTimeout(() => state.counter = 0, 3000)
}
})
看到应用提交了一个RESET变更请求时,我们将预测应用的 状态counter被重置为0,
但现在的问题是当点击按钮的同时couter状态并没有马上变化,而是3秒钟后异步代码执行后才发生改变,这就导致不可预测
未完待续。。。。。