一、前文梳理
流程:
- vuex暴露两个方法
createStore
和useStore
- 调用
createStore
传递过来所有的state、getters、mutations
等 createStore
中调用new Store
方法,产生store实例,传递用户定义的所有的数据new Store
中的install
方法会把store实例放在全局上,确保每个组件可以通过$store
访问,同时通过app.provide(injectKey || storeKey, this)
把store放到app上new Store
调用new ModuleCollection
继续传递数据,ModuleCollection
的register
方法把数据变成一个root树new Store
的installModule
方法把state、getters、mutations
等按照模块划分好useStore
把当前store
注入每个组件:组件中会const store = useStore();
目前状态:
假如每个模块都有同名的add方法,调用时,每一个都会触发
二、实现逻辑
当用户调用方法时,想要实现调用哪个就触发对应的方法,使用发布订阅模式
三、收集getters、mutations、actions
把所有的getters、mutations、actions
收集到store
上
1、在store中创建收集容器
constructor(options) {
const store = this
// options是一个对象,对象中有state、modules等
// 发布订阅模式,用户触发哪个就去调用哪个
store._modules = new ModuleCollection(options)
store._wrappedGetters = Object.create(null);
store._mutations = Object.create(null);
store._actions = Object.create(null);
}
2、定义辅助方法
在modules.js中定义方法
forEachGetter(fn){
if(this._raw.getters){
forEachValue(this._raw.getters,fn)
}
}
forEachMutation(fn){
if(this._raw.mutations){
forEachValue(this._raw.mutations,fn)
}
}
forEachAction(fn){
if(this._raw.actions){
forEachValue(this._raw.actions,fn)
}
}
3、实现收集
在安装时,把所有的对象放到store对应定义的变量上
(1)getter
getter第一个参数为state,此处用store.state因为后续我们会将store.state 用reactive包裹,把数据变成响应式
// 安装的时候 把所有的对象放到store对应定义的变量上,遍历当前模块上所有的getter,
// getters module._raw.getters
module.forEachGetter((getter, key) => { // {double:function(state){}}
// 第一个参数是getter的内容,key为getter的属性名,再去调用原来的方法,
// store._wrappedGetters[key] = getter 这样写没有办法传递参数
store._wrappedGetters[key] = () => {
// 通过这个方法去获取最新的state
// 第一个参数为state,写module.state问题:模块上的状态是自己维护的,不具备响应式的功能
return getter(getNestedState(store.state, path));
}
})
function getNestedState(state, path) { // 根据路径 获取store.上面的最新状态
return path.reduce((state, key) => state[key], state)
}
(2)mutation
// mutation {add:[mutation]}
module.forEachMutation((mutation, key) => {
const entry = store._mutations[key] || (store._mutations[key] = []);
// 把当前的mutation放到entry里面
// 用户store.commit('add',payload),调用entry里面的方法,payload作为参数传递进来
entry.push((payload)=>{
// call:改变this的指向同时让函数mutation立即执行,第一个参数为最新的state,第二个为用户传递的参数
mutation.call(store, getNestedState(store.state, path), payload)
})
});
(3)action
- mutation和action的一个区别, action执行后返回一个是promise,需要判断用户是否写了.then方法
- action既可以调用commit又可以调用dispatch,所以区别于mutation第一个参数传递store
// // store.dispatch('LOGIN',payload).then(()=>{})
module.forEachAction((action, key) => {
const entry = store._actions[key] || (store._actions[key] = []);
// 用户store.dispatch('add',payload),调用entry里面的方法,payload作为参数传递进来
entry.push((payload)=>{
// action既可以调用commit又可以调用dispatch,所以第一个参数传递store
let res = action.call(store, store, payload)
// res 是不是一个promise
if (!isPromise(res)) {
return Promise.resolve(res);
}
return res;
})
});
utils中扩展工具类,判断返回值是不是一个promise
export function isPromise(val) {
return val && typeof val.then === "function";
}
4、实现
(1)定义state和getters
new Store中,定义响应式数据
// 定义响应式数据
resetStoreState(store,state);
get state(){ //目前数据在data中
return this._state.data
}
// 定义响应式数据
unction resetStoreState(store, state) {
// 为了后续变的方便,包一层data
store._state = reactive({ data: state }); //store._state.data = 'xxx'
const wrappedGetters = store._wrappedGetters;
// 循环把每一个
store.getters = {};
forEachValue(wrappedGetters, (getter, key) => {
Object.defineProperty(store.getters, key,{
get: () => getter(),
enumerable: true
});
});
(2)commit和dispatch
在_mutations和_actions中找到对应的方法去触发
commit = (type, payload) => {
const entry = this._mutations[type] || [];
entry.forEach((handler) => handler(payload));
};
dispatch = (type, payload) => {
// 执行完之后是promise
const entry = this._actions[type] || [];
return Promise.all(entry.map((handler) => handler(payload)));
};
(3)测试
actions: {
//可以调用其他action和mutation
asyncAdd({ commit }, payload) {
return new Promise((resolve, reject) => {
setTimeout(() => {
commit("add", payload);
resolve('ok')
}, 1000);
});
},
},
function asyncAdd(){
store.dispatch('asyncAdd',1).then(res=>{
console.log(res)
})
}