前言
昨日写了 commit/state
,今天来看看 dispatch / getter
getter
有时候咱们需要从 state 中得出派生状态,类似于 vue
中的 computed
特点,其实 vuex 也是利用了 computed
比如下面的这个例子:
createStore ({
state:{
age:10
},
getters:{
calAge(state){
//经过 state 的值 获取新的状态
return state.age + 10
}
}
})
运用 _wrappedGetters
包装 getters
class Store<T> {
constructor(options) {
// getter 调集
this._wrappedGetters = Object.create(null)
const store = this
Object.entries(options.getters).forEach(([key, fnValue]) => {
this.registerGetter(store, key, fnValue)
})
}
registerGetter(store: Store<T>, key, handler) {
store._wrappedGetters[key] = function wrappedGetter(store) {
// 不只能够传递 state,也能够传递 getter
return handler(store.state, store.getters)
}
}
}
store.util.js
最后 _wrappedGetters
形如
{
calAge:
function wrappedGetter(store){
return [calAgefn](store.state,store.getters)
}
}
然后执行
function partial(fn, arg) {
return function () {
return fn(arg)
}
}
class Store<T> {
constructor(options) {
Object.entries(options.getters).forEach(([key, fnValue]) => {
this.registerGetter(store, key, fnValue)
})
this.resetStoreState(store)
}
resetStoreState(store){
store.getters = {}
const wrappedGetters = store._wrappedGetters
const computedObj = {}
const computedCache = {}
Object.entries(wrappedGetters).forEach(([key,fn])=>{
computedObj[key] = partial(fn, store)
computedCache[key] = computed(() => computedObj[key]())
Object.defineProperty(store.getters, key, {
get: () => computedCache[key].value,
enumerable: true
})
})
}
}
运用 resetStoreState
进行缓存
这样做有几点优点
- 核算函数fn被缓存在computedObj中,避免每次获取核算特点时都重新创建函数。
- 核算特点被缓存在computedCache中,Vue框架会主动缓存核算特点的核算结果。
- 经过computedObj和computedCache别离函数界说和特点读取,完成了核算函数的复用和结果缓存
最后经过
Object.defineProperty
界说 get 特点,完成了 getter的 可读
dispatch
dispatch
能够触发 在 actions
界说的办法,在 actions
中能够触发 commit/dispatch
,也能够触发异步办法
class Store<T> {
constructor(options) {
this._actions = Object.create(null)
Object.entries(options.actions).forEach(([fnName, fnValue]) => {
this.registerAction(store, fnName, fnValue)
})
}
registerAction(store, type, handler,){
const entry = store._actions[type] || (store._actions[type] = []);
entry.push(function wrappedActionHandler (payload) {
let res = handler.call(store, {
dispatch: store.dispatch,
commit: store.commit,
getters: store.getters,
state: store.state,
}, payload)
if(!res || typeof res.then !== "function"){
res = Promise.resolve(res)
}
})
}
}
store-util.js
这个 dispatch
比较简单
dispatch(type, payload){
const entry = this._actions[type]
if (!entry) {
return
}
const result = entry.length > 1
? Promise.all(entry.map(handler => handler(payload)))
: entry[0](payload)
return new Promise((resolve) => {
result.then(res => {
resolve(res)
})
})
}
类型
type StoreOtpions<T> = {
state?: T
mutations?: Record<string, (s: T, payload: any) => void>,
actions?: Record<string, (s: Store<T>,payload?:any) => void>,
getters?: Record<string, (s: T, getters: StoreOtpions<T>["getters"]) => void>
}
ts 也能推导出 state 类型
整体来说,仍是比较明晰的,也比较简单