Vuex
Vuex 集中式存儲(chǔ)管理應(yīng)用的所有組件的狀態(tài),并以相應(yīng)的規(guī)則保證狀態(tài)以可預(yù)測的方式發(fā)生變化。
核心概念
state 狀態(tài)、數(shù)據(jù) mutations 更改狀態(tài)的函數(shù) actions 異步操作
store 包含以上概念的容器
狀態(tài) - state
state保存應(yīng)用狀態(tài)
export default new Vuex.Store({
state: { counter:0 },
})
狀態(tài)變更 - mutations
mutations用于修改狀態(tài),store.js
export default new Vuex.Store({
mutations: {
add(state) {
state.counter++
} }
})
派生狀態(tài) - getters
從state派生出新狀態(tài),類似計(jì)算屬性
export default new Vuex.Store({
getters: {
doubleCounter(state) { // 計(jì)算剩余數(shù)量 return state.counter * 2;
} }
})
動(dòng)作 - actions
添加業(yè)務(wù)邏輯,類似于controller
export default new Vuex.Store({
actions: {
add({ commit }) {
setTimeout(() => {
commit('add')
}, 1000);
} }
})
vuex原理解析
任務(wù)分析
實(shí)現(xiàn)一個(gè)插件:聲明Store類,掛載$store Store具體實(shí)現(xiàn):
創(chuàng)建響應(yīng)式的state,
保存mutations、actions和getters 實(shí)現(xiàn)commit根據(jù)用戶傳入type執(zhí)行對(duì)應(yīng)mutation
實(shí)現(xiàn)dispatch根據(jù)用戶傳入type執(zhí)行對(duì)應(yīng)action,
同時(shí)傳遞上下文 實(shí)現(xiàn)getters,按照getters定義對(duì)state做派生
初始化:Store聲明、install實(shí)現(xiàn)
let Vue;
class Store {
constructor(options = {}) {
this._vm = new Vue({
data: {
$$state:options.state
}
}); }
get state() {
return this._vm._data.$$state
}
set state(v) {
console.error('please use replaceState to reset state');
} }
function install(_Vue) {
Vue = _Vue;
Vue.mixin({
beforeCreate() {
if (this.$options.store) {
Vue.prototype.$store = this.$options.store;
} }
}); }
export default { Store, install };
實(shí)現(xiàn)commit:根據(jù)用戶傳入type獲取并執(zhí)行對(duì)應(yīng)mutation
class Store {
constructor(options = {}) {
// 保存用戶配置的mutations選項(xiàng)
this._mutations = options.mutations || {}
}
commit(type, payload) {
// 獲取type對(duì)應(yīng)的mutation
const entry = this._mutations[type]
if (!entry) {
console.error(`unknown mutation type: ${type}`);
return
}
// 指定上下文為Store實(shí)例
// 傳遞state給mutation entry(this.state, payload);
} }
實(shí)現(xiàn)actions:根據(jù)用戶傳入type獲取并執(zhí)行對(duì)應(yīng)action
class Store {
constructor(options = {}) {
// 保存用戶編寫的actions選項(xiàng) this._actions = options.actions || {}
// 綁定commit上下文否則action中調(diào)用commit時(shí)可能出問題!! // 同時(shí)也把a(bǔ)ction綁了,因?yàn)閍ction可以互調(diào)
const store = this
const {commit, action} = store
this.commit = function boundCommit(type, payload) {
commit.call(store, type, payload)
}
this.action = function boundAction(type, payload) {
return action.call(store, type, payload)
}
}
dispatch(type, payload) {
// 獲取用戶編寫的type對(duì)應(yīng)的action const entry = this._actions[type]
if (!entry) {
console.error(`unknown action type: ${type}`);
return
}
// 異步結(jié)果處理常常需要返回Promise
return entry(this, payload);
}
}
實(shí)現(xiàn)getter,state的計(jì)算屬性
let Vue;
class Store {
constructor(options) {
// 定義響應(yīng)式的state
// this.$store.state.xx
// 借雞生蛋
let computed={}
Object.keys(options.getters).forEach(function (key) {
computed[key]=function () {
return options.getters[key](options.state)
}
})
console.log(computed)
this._vm = new Vue({
data: {
$$state: options.state
},
computed:computed
})
this._mutations = options.mutations
this._actions = options.actions
// 綁定this指向
this.commit = this.commit.bind(this)
this.dispatch = this.dispatch.bind(this)
}
get getters() {
return this._vm
}
// 只讀
get state() {
return this._vm._data.$$state
}
set state(val) {
console.error('不能直接賦值呀,請(qǐng)換別的方式??!天王蓋地虎!!');
}
// 實(shí)現(xiàn)commit方法,可以修改state
commit(type, payload) {
// 拿出mutations中的處理函數(shù)執(zhí)行它
const entry = this._mutations[type]
if (!entry) {
console.error('未知mutaion類型');
return
}
entry(this.state, payload)
}
dispatch(type, payload) {
const entry = this._actions[type]
if (!entry) {
console.error('未知action類型');
return
}
// 上下文可以傳遞當(dāng)前store實(shí)例進(jìn)去即可
entry(this, payload)
}
}
function install(_Vue){
Vue = _Vue
// 混入store實(shí)例
Vue.mixin({
beforeCreate() {
if (this.$options.store) {
Vue.prototype.$store = this.$options.store
}
}
})
}
// { Store, install }相當(dāng)于Vuex
// 它必須實(shí)現(xiàn)install方法
export default { Store, install }