应用 vue 过程中难免会用到 vuex,然而很多时候咱们只晓得如何应用它但却不明确外部运行机制,上面咱们来简略手写一下 vuex 的实现过程。
简介
Vuex 是一个专为 Vue.js 利用程序开发的 状态管理模式 。其 集中式 的存储了利用所有组件的状态,并且制订了绝对应的规定以便保障组件状态能够朝着 可预测 的方向发生变化。
首先须要理解 vuex 的几个外围概念:
- State 繁多状态树,惟一数据源
- Mutation 状态更改函数
- Action 蕴含任意异步操作
- Getter state 中派生出一些状态,相似计算属性
- Module store 模块宰割机制,
- store 蕴含以上概念的容器
对这些概念不分明的能够观看 vuex 官网进行进一步理解:https://vuex.vuejs.org/zh/
vuex 原理解析
首先 vuex 是一个插件,咱们须要去申明一个 store 类,还要有个 install 办法去挂载 $store。
store 的具体实现过程:
1、创立响应式的 state, 保留 mutations,actions 与 getters。
2、实现 commit 依据用户传入 type 执行对应 mutation。
3、实现 dispatch 依据传入的 type 生成对应的 action,同时传递数据。
4、实现 getters,依照 getters 定义对 state 派生数据。
首先设计 vuex 根本数据:
import Vue from 'vue'
import Vuex from './vuex'
Vue.use(Vuex)
export default new Vuex.Store({
state: {counter: 0,},
mutations: {add(state) {state.counter++}
},
actions: {
// 参数怎么来的?add({commit}) {
// 业务逻辑组合或者异步
setTimeout(() => {commit('add')
}, 1000);
}
},
getters: {
doubleCounter: state => {return state.couter*2;},
},
modules: {}})
1. 对 store 类的申明,install 办法实现。
let Vue;
// 申明 Store 类
class Store {constructor(options = {}) {
this._vm = new Vue({
// data 中的值都会做响应化解决
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) {
// this.$options 为 Vue 实例的初始化选项
Vue.prototype.$store = this.$options.store;
}
}
});
}
export default {Store, install};
这里有两点值得注意,源码中 state 利用 vue 的 data 的响应式。利用存取器,把 state 设置成只读属性。
这里双 $ 定义 state 第一次看上去必定有点不解,这里是为了 Vue 不做代理。
2. 实现 commit: 依据用户传入 type 获取并执行对应 mutation
class Store {constructor(options = {}) {
// 保留用户配置的 mutations 选项
this._mutations = options.mutations || {}}
commit(type, payload) {
// 获取 type 对应的 mutation
const entry = this._mutations[type]
if (!entry) {console.error(`unknown mutation type: ${type}`);
return
}
// 指定上下文为 Store 实例
// 传递 state 给 mutation entry(this.state, payload);
entry(this.state, payload)
}
}
这里的 entry 是 mutations 外面定义的 add 办法,payload 是传入的参数。
3. 实现 actions: 依据用户传入 type 获取并执行对应 action
class Store {constructor(options) {
this._actions = options.actions
// 锁死 commit,dispatch 函数 this 指向
const store = this
const {commit, dispatch} = store
this.commit = function boundCommit(type, payload) {commit.call(store, type, payload)
}
this.dispatch = function boundDispatch(type, payload) {dispatch.call(store, type, payload)
}
}
// dispatch,执行异步工作或简单逻辑
dispatch(type, payload) {
// 1. 获取 action
const entry = this._actions[type]
if (!entry) {console.error('哎呦,没有这个 action');
return;
}
// 异步后果解决经常须要返回 Promise
return entry(this, payload)
}
}
这里对 dispatch 和 commit 做了 this 的绑定,必须绑定 commit 上下文否则 action 中调用 commit 时可能出问题
3. 实现 getters:state 的动静计算属性
class Store {constructor(options) {
const store = this
this._wrappedGetters = options.getters
// 定义 computed 选项
const computed = {}
this.getters = {}
Object.keys(this._wrappedGetters).forEach(key => {
// 获取用户定义的 getter
const fn = store._wrappedGetters[key]
// 转换为 computed 能够应用无参数模式
computed[key] = function() {return fn(store.state)
}
// 为 getters 定义只读属性
Object.defineProperty(store.getters, key, {get: () => store._vm[key]
})
})
this._vm = new Vue({
// data 中的值都会做响应化解决
data: {$$state: options.state},
// 利用 vue 的 computed 计算属性
computed
})
}
这里看起来简单认真拆分每一个看,其实很简略。
最终实现成果