前言
在上一篇文章中我们实现了手写JavaScript事件总线,这次我们准备结合之前我们所实现的事件总线来实现全局状态管理的功能,上篇文章链接:juejin.cn/post/718837…
需求分析
如果有使用过 Vuex、Pinia 的朋友都应该知道在使用他们的时候一般要传一个对象,这个对象里面至少会有两个属性,分别是 state、actions,这两个参数就不过多解释。我们只需要了解我们所实现的功能方法,大概包括如下几点:
- onState(stateKey, eventCallback) 监听 state 的单个数据的改变
- onStates(stateKeys, eventCallback) 监听 state 中多个数据的改变
- offState(stateKey, eventCallback) 移除监听 state 单个数据的事件函数
- offStates(stateKeys, eventCallback) 移除多个监听 state 数据的事件函数
- setState(stateKey, newValue) 设置 state 数据
- dispatch(actionKey, ...args) 执行 actions 中的 方法
编写代码
编写结构
// 上篇文章所实现的事件总线
const AriesEventBus = require("./event-bus");
class AriesEventStore {
// 初始化操作
constructor(options) {}
// 给 state 中的每个属性添加属性描述符
_observe() {}
// 监听 state 中单个数据的改变
onState(stateKey, eventCallback) {}
// 监听 state 中多个数据的改变
onStates(stateKeys, eventCallback) {}
// 移除 state 中单个数据的对应的监听函数
offState(stateKey, eventCallback) {}
// 移除 state 中多个数据的对应的监听函数
offStates(stateKeys, eventCallback) {}
// 设置 state 中的数据
setState(stateKey, newValue) {}
// 执行 actions 中对应的方法
dispatch(actionKey, ...args) {}
}
实现初始化操作和 _observe() 方法
// 初始化函数
constructor(options) {
// 判断传入的 state 和 actions 是否是对象类型
if (typeof options.state !== "object") {
throw new TypeError("state 必须为 object 类型")
}
if (typeof options.actions !== "object") {
throw new TypeError("actions 必须为 object 类型")
}
// 遍历 actions,判断 actions 中的属性值是否为方法
const actionsValues = Object.values(options.actions)
for (const action of actionsValues) {
if (typeof action !== "function") {
throw new TypeError("actions 中的每个属性值必须为 function 类型")
}
}
this.actions = options.actions
this.state = options.state
// event:监听或移除单个
this.event = new AriesEventBus()
// eventV2:监听或移除多个
this.eventV2 = new AriesEventBus()
this._observe()
}
// 给 state 中的每个属性添加属性描述符
_observe() {
let _this = this
Object.keys(this.state).forEach(key => {
let _value = this.state[key]
Object.defineProperty(this.state, key, {
get() {
return _value
},
set(newValue) {
if (newValue === _value) return
_value = newValue
/**
* event和eventV2其实就是实例化后的 eventBus
* 在 内部的 emit() 方法中如果 key 不存在于 eventBUs上
* 则不会执行
*/
// 在修改state的时候触发单个 key 的监听操作
_this.event.emit(key, newValue)
// 在修改state的时候触发多个 key 的监听操作
_this.eventV2.emit(key, {[key]: newValue})
}
})
})
}
实现 onState() 和 onStates()
// 监听 state 中单个数据的改变
onState(stateKey, eventCallback) {
if (Object.keys(this.state).indexOf(stateKey) === -1) {
throw Error("state 中不存在这个key:" + stateKey)
}
this.event.on(stateKey, eventCallback, this.state)
eventCallback.apply(this.state, [this.state[stateKey]])
}
// 监听 state 中多个数据的改变
onStates(stateKeys, eventCallback) {
if (!Array.isArray(stateKeys)) {
throw new TypeError("stateKeys必须为 Array 类型")
}
const keys = Object.keys(this.state)
const value = {}
for (const key of stateKeys) {
if (keys.indexOf(key) === -1) {
throw Error("state 中不存在这个 key:" + key)
}
this.eventV2.on(key, eventCallback)
value[key] = this.state[key]
}
eventCallback.apply(this.state, [value])
}
实现 offState() 和 offStates()
// 移除 state 中单个数据的对应的监听函数
offState(stateKey, eventCallback) {
if (Object.keys(this.state).indexOf(stateKey) === -1) {
throw Error("state 中不存在这个 key:" + key)
}
this.event.off(stateKey, eventCallback)
}
// 移除 state 中多个数据的对应的监听函数
offStates(stateKeys, eventCallback) {
if (!Array.isArray(stateKeys)) {
throw new TypeError("stateKeys必须为 Array 类型")
}
const keys = Object.keys(this.state)
for (const key of stateKeys) {
if (keys.indexOf(key) === -1) {
throw Error("state 中不存在这个 key:" + key)
}
this.eventV2.off(key, eventCallback)
}
}
实现 setState() 和 dispatch()
// 设置 state 中的数据
setState(stateKey, newValue) {
if (Object.keys(this.state).indexOf(stateKey) === -1) {
throw Error("state 中不存在这个key:" + stateKey)
}
this.state[stateKey] = newValue
}
// 执行 actions 中对应的方法
dispatch(actionKey, ...args) {
if (Object.keys(this.actions).indexOf(actionKey) === -1) {
throw Error("actions 中没有这个属性名:" + actionKey)
}
const action = this.actions[actionKey]
action.apply(this, [this.state, args])
}
完整代码
const AriesEventBus = require("./event-bus");
class AriesEventStore {
// 初始化函数
constructor(options) {
// 判断传入的 state 和 actions 是否是对象类型
if (typeof options.state !== "object") {
throw new TypeError("state 必须为 object 类型")
}
if (typeof options.actions !== "object") {
throw new TypeError("actions 必须为 object 类型")
}
// 遍历 actions,判断 actions 中的属性值是否为方法
const actionsValues = Object.values(options.actions)
for (const action of actionsValues) {
if (typeof action !== "function") {
throw new TypeError("actions 中的每个属性值必须为 function 类型")
}
}
this.actions = options.actions
this.state = options.state
// event:监听或移除单个
this.event = new AriesEventBus()
// eventV2:监听或移除多个
this.eventV2 = new AriesEventBus()
this._observe()
}
// 给 state 中的每个属性添加属性描述符
_observe() {
let _this = this
Object.keys(this.state).forEach(key => {
let _value = this.state[key]
Object.defineProperty(this.state, key, {
get() {
return _value
},
set(newValue) {
if (newValue === _value) return
_value = newValue
/**
* event和eventV2其实就是实例化后的 eventBus
* 在 内部的 emit() 方法中如果 key 不存在于 eventBUs上
* 则不会执行
*/
// 在修改state的时候触发单个 key 的监听操作
_this.event.emit(key, newValue)
// 在修改state的时候触发多个 key 的监听操作
_this.eventV2.emit(key, {[key]: newValue})
}
})
})
}
// 监听 state 中单个数据的改变
onState(stateKey, eventCallback) {
if (Object.keys(this.state).indexOf(stateKey) === -1) {
throw Error("state 中不存在这个key:" + stateKey)
}
this.event.on(stateKey, eventCallback, this.state)
eventCallback.apply(this.state, [this.state[stateKey]])
}
// 监听 state 中多个数据的改变
onStates(stateKeys, eventCallback) {
if (!Array.isArray(stateKeys)) {
throw new TypeError("stateKeys必须为 Array 类型")
}
const keys = Object.keys(this.state)
const value = {}
for (const key of stateKeys) {
if (keys.indexOf(key) === -1) {
throw Error("state 中不存在这个 key:" + key)
}
this.eventV2.on(key, eventCallback)
value[key] = this.state[key]
}
eventCallback.apply(this.state, [value])
}
// 移除 state 中单个数据的对应的监听函数
offState(stateKey, eventCallback) {
if (Object.keys(this.state).indexOf(stateKey) === -1) {
throw Error("state 中不存在这个 key:" + key)
}
this.event.off(stateKey, eventCallback)
}
// 移除 state 中多个数据的对应的监听函数
offStates(stateKeys, eventCallback) {
if (!Array.isArray(stateKeys)) {
throw new TypeError("stateKeys必须为 Array 类型")
}
const keys = Object.keys(this.state)
for (const key of stateKeys) {
if (keys.indexOf(key) === -1) {
throw Error("state 中不存在这个 key:" + key)
}
this.eventV2.off(key, eventCallback)
}
}
// 设置 state 中的数据
setState(stateKey, newValue) {
if (Object.keys(this.state).indexOf(stateKey) === -1) {
throw Error("state 中不存在这个key:" + stateKey)
}
this.state[stateKey] = newValue
}
// 执行 actions 中对应的方法
dispatch(actionKey, ...args) {
if (Object.keys(this.actions).indexOf(actionKey) === -1) {
throw Error("actions 中没有这个属性名:" + actionKey)
}
const action = this.actions[actionKey]
action.apply(this, [this.state, args])
}
}
测试
const eventStore = new AriesEventStore({
state: {
name: "coder",
age: 18
},
actions: {
test(ctx, payload) {
console.log(ctx);
console.log(payload);
}
}
})
function nameCallback(...args) {
console.log(args);
}
function manyCallback(...args) {
console.log(args);
}
eventStore.onState('name', nameCallback)
eventStore.onStates(['name', 'age'], manyCallback)
setTimeout(() => {
eventStore.setState('name', "zjl")
}, 1000);
setTimeout(() => {
eventStore.offState('name', nameCallback)
}, 2000)
setTimeout(() => {
eventStore.setState('name', "涂发亮")
eventStore.setState('age', 30)
}, 3000);
setTimeout(() => {
eventStore.dispatch('test', "I", "want", "you")
}, 4000);