hy-event-store
hy-event-store
English · 简体中文
hy-event-store 是一个零运行时依赖的事件总线与浅层全局状态管理库。它不绑定框架,可用于支持 CommonJS 包的 JavaScript 工程,包括常见的 Vue、React 和小程序构建流程。
特性
- 零运行时依赖
- 支持回调上下文、一次性监听和显式清理的事件总线
- 支持单个和多个状态键订阅的共享状态
dispatch原样返回同步结果或 Promise- Node.js 18、20、22、24、26 的自动化测试与 CI
安装
npm install hy-event-store
当前包提供 CommonJS 入口,并内置第一方 TypeScript 声明:
const { HYEventBus, HYEventStore } = require("hy-event-store")
TypeScript 用户无需改变运行时 API,即可补充事件和状态类型:
const bus = new HYEventBus<{ ready: []; signedIn: [user: { name: string }] }>()
bus.on("signedIn", user => console.log(user.name))
const store = new HYEventStore({
state: { count: 0 },
actions: {
increment(state, amount: number) {
state.count += amount
return state.count
}
}
})
小程序项目接入
当前发布包使用 CommonJS。在微信开发者工具中,请启用使用 npm 模块, 执行构建 npm,然后使用包名导入:
const { HYEventStore } = require("hy-event-store")
不要直接导入 src/event-store.js 或 store/hy-event-store.js 这类路径。
这些路径指向源码文件,并不是构建后的小程序模块入口。如果使用其他构建
工具,请配置它从 node_modules 解析 CommonJS 包,并保持使用包名导入。
快速开始
事件总线
const { HYEventBus } = require("hy-event-store")
const bus = new HYEventBus()
function handleSignedIn(user) {
console.log(user.name)
}
bus.on("signed-in", handleSignedIn)
bus.emit("signed-in", { name: "Ada" })
bus.off("signed-in", handleSignedIn)
使用 once 注册只处理一次的事件:
bus.once("ready", () => {
console.log("只会执行一次")
})
若回调需要组件或页面实例作为 this,请传入第三个参数:
const page = {
title: "个人资料",
render(user) {
console.log(this.title, user.name)
}
}
bus.on("user-updated", page.render, page)
bus.emit("user-updated", { name: "Ada" })
bus.off("user-updated", page.render)
共享状态
const { HYEventStore } = require("hy-event-store")
const store = new HYEventStore({
state: {
count: 0,
status: "idle"
},
actions: {
increment(state, amount = 1) {
state.count += amount
return state.count
},
async load(state, request) {
state.status = "loading"
const result = await request()
state.status = "ready"
return result
}
}
})
function renderCount(count) {
console.log("当前计数:", count)
}
store.onState("count", renderCount)
store.setState("count", 1)
store.offState("count", renderCount)
const count = store.dispatch("increment", 2)
async function loadData() {
return store.dispatch("load", () => fetch("/api/data").then(res => res.json()))
}
onState 会先立即以当前值调用一次回调,之后在对应状态键变更时再次调用。
如需读取一个已声明的状态值,但不订阅更新,可以使用:
const status = store.getState("status")
getState 不会通知监听器,读取未声明的键时会抛出错误。它会原样
返回当前值,不会创建深拷贝,也不是深层只读快照。
使用 onStates 订阅多个状态键:
function renderProfile(change) {
console.log(change)
}
store.onStates(["count", "status"], renderProfile)
// 首次回调:{ count: 0, status: "idle" }
// 后续 setState("count", 1) 后:{ count: 1 }
store.offStates(["count", "status"], renderProfile)
API 说明
HYEventBus
| 方法 | 作用 | 返回值 |
|---|---|---|
on(eventName, callback, thisArg?) |
注册监听器。 | 事件总线实例 |
once(eventName, callback, thisArg?) |
注册仅在第一次触发时执行的监听器。 | 事件总线实例 |
emit(eventName, ...payload) |
通知某个事件的全部监听器。 | 事件总线实例 |
off(eventName, callback) |
移除通过 on 或 once 注册的回调;事件不存在时也可安全调用。 |
事件总线实例 |
clear() |
清除全部事件的监听器。 | 事件总线实例 |
hasEvent(eventName) |
判断事件是否至少有一个监听器。 | 布尔值 |
事件名称必须为字符串。事件触发时会使用稳定的监听器快照,因此一次性监听器自行移除时不会跳过下一个监听器。
HYEventStore
创建 Store 时必须提供 state 对象,actions 为可选对象。每个 action 都必须是函数,且第一个参数为 state。
| 方法 | 作用 |
|---|---|
onState(key, callback) |
订阅一个已声明的状态键,并立即收到当前值。 |
offState(key, callback) |
取消单状态订阅。 |
onStates(keys, callback) |
订阅多个已声明状态键,并立即收到初始快照;后续回调只包含变化的键。 |
offStates(keys, callback) |
取消多状态订阅。 |
setState(key, value) |
更新已声明的状态键。 |
getState(key) |
读取一个已声明的状态值,不建立订阅。 |
dispatch(actionName, ...args) |
运行 action,并原样返回它的结果,包括 Promise。 |
使用注意事项
- 所有需要监听的状态键必须在初始
state对象中声明。更新未知键会抛出错误,避免产生不可观察的状态。 - Store 是浅层监听:替换
state.profile会触发监听;直接修改state.profile.name不会触发。 - 使用严格相等判断;赋值相同值不会触发更新。
- 请保留稳定的回调引用,并在组件或页面销毁时调用
off、offState或offStates,避免页面切换后重复监听。 - 小程序中如需在回调内使用页面
this,注册时传入页面实例作为thisArg,并在页面清理生命周期中取消同一个回调。
兼容性
发布包为 CommonJS,且没有运行时依赖。CI 在 Node.js 18 至 26 上验证。浏览器和小程序项目应通过各自的 npm 包构建或打包流程使用本包。
原生 ESM 导出、只读状态选择器与 onStates 的完整快照模式属于后续设计项,详见路线图。
开发
npm ci
npm test
npm run test:coverage
npm pack --dry-run
贡献与安全
- 提交 PR 前请阅读 CONTRIBUTING.md。
- 安全问题请按照 SECURITY.md 私下报告。
- 后续计划请查看 ROADMAP.md。
许可证
MIT © coderwhy
Related Packages
A package to avoid repetition with Routes, Links and URLs, and reduce boilerplat...
Used to bundle and serve manifests web component that build on any UI frameworks...
Version History
| Version | Released | License |
|---|---|---|
| 1.4.1 | MIT | |
| 1.4.0 | MIT | |
| 1.3.1 | MIT | |
| 1.2.1 | MIT | |
| 1.2.0 | MIT | |
| 1.1.1 | MIT | |
| 1.1.0 | MIT | |
| 1.0.0 | MIT |