通过学习和理解,实现一个简易版的vuex
原理
各个组件状态管理,通过vue提供的依赖注入provide
\ inject
方法实现
1. createStore
首先创建一个Store类。创建实例后,app.use
安装插件,向组件提供键值为store
的值
javascript
export function createStore(options) {
return new Store(options);
}
class Store {
// vue中app.use需要install
install(app) {
app.provide('store', this);
}
}
2. useStore
使用时需要注入store,获取对应store
键值提供的值并返回
javascript
import { inject } from 'vue'
export function useStore() {
return inject('store');
}
State
- state有两种使用方式,一是函数返回,二是普通对象
- state需要通过
reactive
实现响应式 - state的值只能通过
commit
进行修改,直接设置store.state是禁止的
javascript
class Store {
constructor(options) {
this._modules = new ModuleCollection(options);
// 获取state
const state = this._modules.root.state;
// 重置(初始化)getters及配置getters的compute
resetStoreState(this, state);
}
get state() {
return this._state.data;
}
set state(value) {
// 禁止直接修改state
console.log('禁止直接修改state');
}
}
function resetStoreState(store, state) {
// 设置数据响应式,这一步最重要
store._state = reactive({
data: state,
});
}
class ModuleCollection {
constructor(options) {
this.register(options);
}
register(rawState) {
// 注册根对象
this.root = new Module(rawState);
}
}
class Module {
constructor(rawModule) {
this.state = typeof rawModule.state === 'function' ? rawModule.state() : rawModule.state;
}
}
getters
javascript
class Store {
constructor(options) {
this._modules = new ModuleCollection(options);
this._wrappedGetters = Object.create(null);
...
for (const gettersKey in options.getters) {
registerGetters(this, gettersKey, options.getters[gettersKey]);
}
// 重置(初始化)getters及配置getters的compute
resetStoreState(this, state);
}
...
}
function resetStoreState(store, state) {
...
store.getters = {};
for (const gettersKey in store._wrappedGetters) {
Object.defineProperty(store.getters, gettersKey, {
get() {
const data = computed(() => store._wrappedGetters[gettersKey]());
return data.value;
},
enumerable: true,
})
}
}
function registerGetters(store, type, getters) {
// 赋值到_wrappedGetters
store._wrappedGetters[type] = () => {
return getters(store.state); // 相当于使用时state的传值,例count(state) { return state.count }
}
}
mutations
commit
方法中执行对应的mutations
中所有函数,同步执行
javascript
class Store {
constructor(options) {
this._modules = new ModuleCollection(options);
this._wrappedGetters = Object.create(null);
this._mutations = Object.create(null);
...
for (const mutationsKey in options.mutations) {
registerMutation(this, mutationsKey, options.mutations[mutationsKey])
}
...
}
...
commit(type, payload) {
const entry = this._mutations[type];
entry.forEach(fn => {
fn(payload)
});
}
}
function registerMutation(store, type, mutation) {
// 赋值到_mutations
const entry = store._mutations[type] || (store._mutations[type] = []);
entry.push(function (payload) {
mutation.call(store, store.state, payload);
});
}
actions
- 在dispatch方法调用时,需要重新绑定dispath和commit的this指向
dispatch
方法中通过Promise.all
同时执行对应的mutations
中所有函数,支持异步执行
javascript
class Store {
constructor(options) {
this._modules = new ModuleCollection(options);
this._wrappedGetters = Object.create(null);
this._mutations = Object.create(null);
this._actions = Object.create(null);
...
for (const actionsKey in options.actions) {
registeAction(this, actionsKey, options.actions[actionsKey])
}
// 需要重新绑定dispath和commit的this指向
const store = this
const { dispatch, commit } = this
this.dispatch = function boundDispatch (type, payload) {
return dispatch.call(store, type, payload)
}
this.commit = function boundCommit (type, payload) {
return commit.call(store, type, payload)
}
// 重置(初始化)getters及配置getters的compute
resetStoreState(this, state);
}
...
dispatch(type, payload) {
const _this = this;
const entry = this._actions[type];
if (!entry) {
return
}
const result = Promise.all(entry.map(handler => {
handler.call(_this, payload)
}));
return new Promise((resolve, reject) => {
result.then((res) => {
resolve(res);
})
})
}
}
function registeAction(store, type, action) {
// 赋值到_actions
const entry = store._actions[type] || (store._actions[type] = []);
entry.push(function (payload) {
action.call(store, {
state: store.state,
// commit: (type, payload) => store.commit.call(store, type, payload),
commit: store.commit,
// dispatch: (type, payload) => store.dispatch.call(store, type, payload),
dispatch: store.dispatch,
}, payload);
});
}
如果commit
和dispatch
未重新绑定this,下述registerAction
中引入这两个方法会出现this指向错误
javascript
function registeAction(store, type, action) {
...
entry.push(function (payload) {
action.call(store, {
state: store.state,
commit: store.commit,
dispatch: store.dispatch,
}, payload);
});
}
// 可修改为,如下写法
function registeAction(store, type, action) {
...
entry.push(function (payload) {
action.call(store, {
state: store.state,
commit: (type, payload) => store.commit.call(store, type, payload),,
dispatch: (type, payload) => store.dispatch.call(store, type, payload),
}, payload);
});
}
完整代码
javascript
import { computed, inject, reactive } from 'vue'
export function createStore(options) {
return new Store(options);
}
export function useStore() {
return inject('store');
}
class Store {
constructor(options) {
this._modules = new ModuleCollection(options);
this._wrappedGetters = Object.create(null);
this._mutations = Object.create(null);
this._actions = Object.create(null);
// 获取state
const state = this._modules.root.state;
for (const gettersKey in options.getters) {
registerGetters(this, gettersKey, options.getters[gettersKey]);
}
for (const mutationsKey in options.mutations) {
registerMutation(this, mutationsKey, options.mutations[mutationsKey])
}
for (const actionsKey in options.actions) {
registeAction(this, actionsKey, options.actions[actionsKey])
}
const store = this
const { dispatch, commit } = this
this.dispatch = function boundDispatch (type, payload) {
return dispatch.call(store, type, payload)
}
this.commit = function boundCommit (type, payload) {
return commit.call(store, type, payload)
}
// 重置(初始化)getters及配置getters的compute
resetStoreState(this, state);
}
get state() {
return this._state.data;
}
set state(value) {
// 禁止直接修改state
console.log('禁止直接修改state');
}
install(app) {
app.provide('store', this);
}
commit(type, payload) {
console.log('commit-this', this);
const entry = this._mutations[type];
entry.forEach(fn => {
fn(payload)
});
}
dispatch(type, payload) {
const _this = this;
console.log('_this', _this);
const entry = this._actions[type];
if (!entry) {
return
}
const result = Promise.all(entry.map(handler => {
console.log('handler', handler);
handler.call(_this, payload)
}));
return new Promise((resolve, reject) => {
result.then((res) => {
resolve(res);
})
})
}
}
class ModuleCollection {
constructor(options) {
this.register(options);
}
register(rawState) {
// 注册根对象
this.root = new Module(rawState);
}
}
class Module {
constructor(rawModule) {
this.state = typeof rawModule.state === 'function' ? rawModule.state() : rawModule.state;
}
}
function resetStoreState(store, state) {
// 设置数据响应式,这一步最重要
store._state = reactive({
data: state,
});
store.getters = {};
for (const gettersKey in store._wrappedGetters) {
console.log(store._wrappedGetters[gettersKey]);
Object.defineProperty(store.getters, gettersKey, {
get() {
const data = computed(() => store._wrappedGetters[gettersKey]());
return data.value;
},
enumerable: true,
})
}
}
function registerGetters(store, type, getters) {
// 赋值到_wrappedGetters
store._wrappedGetters[type] = () => {
return getters(store.state); // 相当于使用时state的传值,例count(state) { return state.count }
}
}
function registerMutation(store, type, mutation) {
// 赋值到_mutations
const entry = store._mutations[type] || (store._mutations[type] = []);
entry.push(function (payload) {
mutation.call(store, store.state, payload);
});
}
function registeAction(store, type, action) {
// 赋值到_actions
const entry = store._actions[type] || (store._actions[type] = []);
entry.push(function (payload) {
action.call(store, {
state: store.state,
// commit: (type, payload) => store.commit.call(store, type, payload),
commit: store.commit,
// dispatch: (type, payload) => store.dispatch.call(store, type, payload),
dispatch: store.dispatch,
}, payload);
});
}