状态管理
状态的初始化
状态管理,我们应该并不陌生。
举个例子,超市里新进了一批商品,管理员给这些商品分类,建立索引,然后按照顺序放入货架的过程就是最简单的状态管理。
let goods1 = { category: 'fruit', name: 'apple', quantity: 5}let goods2 = { category: 'supplies', name: 'toothbrush', quantity: 5}let goods3 = { category: 'clothes', name: 'sweater', quantity: 5}
简单归类后 :
let shop = { goods: { fruit: [{ name: 'apple', quantity: 5 }], supplies: [{ name: 'toothbrush', quantity: 5 }], clothes: [{ name: 'sweater', quantity: 5 }] }}
这样,当我们需要某一商品时,很容易根据类目检索到这个商品 :
console.log(shop.goods.fruit.find(f => f.name === 'apple'))//-> { name: 'apple', quantity: 5 }
状态的改变
当有顾客前来购买商品时,我们需要类似的操作来减少被购买商品的数量 :
shop.goods.fruit.find(f => f.name === 'apple').quantity --
然而在成千上万的交易量背后,你不知道这些商品被购买的详细情况,你甚至不知道上周卖出了多少苹果,你也就无从得知下周该进多少。
所以你需要一个账目来记录商品购买明细 :
let account = { appleSold (value) { console.log("apple sold " + value) shop.goods.fruit.find(f => f.name === 'apple').quantity -= value }}
当卖出苹果时,POS机“滴”一声,记录生成了 :
account.appleSold (5)//-> apple sold 5
最简单的store
于是,我们得到了一个最简单的store :
let shop = { goods: { fruit: [{ name: 'apple', quantity: 5 }], supplies: [{ name: 'toothbrush', quantity: 5 }], clothes: [{ name: 'sweater', quantity: 5 }] }, account: { appleSold (value) { console.log("apple sold " + value) shop.goods.fruit.find(f => f.name === 'apple').quantity -= value }, funcN () { } }}
由此可知,状态管理可以帮助我们更友好的改变状态,同时,跟踪状态变化的轨迹。
Vue(x) er 须知
开始
Vuex 官方文档:
Vuex最核心的概念 :
- Vuex 的状态存储是响应式的。当 Vue 组件从 store 中读取状态的时候,若 store 中的状态发生变化,那么相应的组件也会相应地得到高效更新。
- 你不能直接改变 store 中的状态。改变 store 中的状态的唯一途径就是显式地提交 (commit) mutation。这样使得我们可以方便地跟踪每一个状态的变化,从而让我们能够实现一些工具帮助我们更好地了解我们的应用。
下面对此拓展:
对象引用
下面这两段代码将输出什么? 先不要往下看, 自己写一下
let store = { state: { msg: "welcome" }}, copy = store.state;store.state = { hello: "world"};console.log(Object.keys(copy));
let store = { state: { msg: 'welcome' }}, copy = store.state;store.state.hello = "world";console.log(Object.keys(copy))
结果如下(如果你都答对了,那么理解和上手Vuex将会很轻松) :
//-> ["msg"]//-> ["msg", "hello"]
提交和分发
vuex 只是一个工具,或许过了这段时间,过了这个项目,你就不会再用它。
我们要记住的是它留给我们的启示:
不要直接更改状态, 而是通过提交(commit)和分发(dispatch)的方法通知管理者改变对象状态,这是大型项目和复杂状态管理的最佳实践。
Vuex 核心概念
一个完整的 Vuex Store
/** * index.js */import axios from 'axios'const store = new Vuex.Store({ state: { counter: 0 }, getters: { counter: state => state.counter }, // 可处理异步请求, dispatch 触发 actions: { askPermission ({commit}) { axios.get('/url').then((res) => { if(res.data.permission) commit('addCounter') }).catch((err) => { console.log('Error: in process "Ask permission".\n Detailed: ' + err) }) } }, // 同步, commit 触发 mutations: { addCounter (state) { state.counter ++ } }})
PS: 仔细研究一下 dispatch & actions, commit & mutations, 是否有一种似曾相识的感觉?
Look, 看这对 emit & on (事件机制),同样的事件类型,同样的回调函数。
State
单一状态树
Vuex使用单一状态树,一个state对象包含全部应用层状态,使得一个应用只有唯一数据源(SSOT, Single Source of Truth)
这对模块化并不造成影响
state: { moduleA: { }, moduleB: { }}
Getter
state: { prop: ''}
你可以使用store.state.prop直接读取状态的值, 当然也可以使用Getter :
getters: { prop = state => state.prop}
使用Getter的好处在于,你可以从state中派生出一些状态 :
getters: { prop = state => state.prop, fixedProp = state => state.prop || '暂无'}
Mutation
Vuex 中的 mutation 类似于事件,有一个字符串的 事件类型 (type) 和 一个 回调函数 (handler),回调函数的接受state作为第一个参数,我们在这里修改状态(state)
state: { counter: 0},mutations: { addCounter (state) { state.counter ++ }, addCounter (state, payload) { state.counter += payload.value }}
通过 commit 通知状态变化
store.commit('addCounter')store.commit('addCounter', {value: 1})
Action
类似于mutation,不同在于
- 只能通过 commit mutation 通知状态变化
- mutation 只能包含同步操作,而 action 可以包含异步操作(比如, 在这里可以执行ajax请求)
actions: { askPermission ({commit}) { axios.get('/url').then((res) => { if(res.data.permission) commit('addCounter') }).catch((err) => { console.log('Error: in process "Ask permission".\n Detailed: ' + err) }) }, askPermission ({commit}, payload) { axios.get('/url', { params:payload }).then((res) => { if(res.data.permission) commit('addCounter') }).catch((err) => { console.log('Error: in process "Ask permission".\n Detailed: ' + err) }) }}
通过 dispatch 通知状态变化
store.dispatch('askPermission')store.dispatch('askPermission', { author: "lonelydawn" })
Module
Vuex 允许我们将store分割成模块,每个模块拥有自己的state, mutation, action, getter, 甚至是嵌套子模块 :
const store = new Vuex.Store({ modules: { a: { state: {}, mutations: { addCounter(state) {} }, actions: {}, getters: {} }, b: { namespaced: true, // 建立命名空间 state: {}, mutations: { addCounter(state) {} }, actions: {} } }})store.state.astore.state.b// 提交 给 模块 a 的 mutationsstore.commit('addCounter')// 提交 给 模块 b 的 mutationsstore.commit('b/addCounter')
最后
Vuex 的基本用法已经介绍完了。
相关内容 :
在下列内容中, 我将 演示如何使用 vue + vuex 以及其他常用组件从入门到实战。