-
Notifications
You must be signed in to change notification settings - Fork 315
[v1.3] 改良代码 - subscribeMessage & HookManager #1210
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[v1.3] 改良代码 - subscribeMessage & HookManager #1210
Conversation
cyfung1031
commented
Feb 6, 2026
- 抽出 subscribeMessage。 subscribeMessage的设计不需要 useAppContext
- 加入 HookManager 统一管理,避免 closure GC 问题
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull request overview
该 PR 将页面侧的消息订阅能力从 AppContext 中抽离为全局工具函数 subscribeMessage,并引入 HookManager 统一管理订阅清理与挂载状态,减少组件内手写 unhooks/isMounted 的样板代码,从而降低闭包/清理相关问题风险。
Changes:
- 抽出
subscribeMessage到src/pages/store/global.ts,不再通过useAppContext暴露 - 新增
HookManager,统一管理 effect 清理(unhook)与挂载状态(isMounted) - 多个页面/Hook 迁移为使用
subscribeMessage + HookManager,并更新相关单测 mock
Reviewed changes
Copilot reviewed 9 out of 9 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
| tests/pages/popup/App.test.tsx | 补充 mock subscribeMessage 以适配新的全局导出 |
| tests/pages/options/MainLayout.test.tsx | 同上,补充 mock subscribeMessage |
| src/pkg/utils/hookManger.ts | 新增 HookManager,用于集中管理卸载清理与 isMounted 状态 |
| src/pages/store/global.ts | 新增全局 subscribeMessage,从 Context 内抽离 |
| src/pages/store/AppContext.tsx | 移除 Context 内 subscribeMessage,实现改为直接使用全局 subscribeMessage + HookManager |
| src/pages/popup/App.tsx | 迁移订阅与 isMounted 逻辑到 HookManager,移除对 useAppContext 的依赖 |
| src/pages/options/routes/Setting.tsx | 迁移订阅清理逻辑到 HookManager,并改用全局 subscribeMessage |
| src/pages/options/routes/ScriptList/hooks.tsx | 迁移订阅清理逻辑到 HookManager,并改用全局 subscribeMessage |
| src/pages/batchupdate/App.tsx | 移除 useAppContext 依赖,改用全局 subscribeMessage |
src/pkg/utils/hookManger.ts
Outdated
| private unhooks: ((...args: any) => any)[] | null = []; | ||
| public append(...fns: ((...args: any) => any)[]) { | ||
| this.unhooks!.push(...fns); | ||
| } | ||
| public readonly unhook = () => { | ||
| this.isMounted = false; | ||
| for (const unhook of this.unhooks!) unhook(); | ||
| this.unhooks!.length = 0; |
Copilot
AI
Feb 12, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
HookManager 目前通过非空断言使用 this.unhooks(append / unhook 内的 this.unhooks!)。如果 unhook 被重复调用,或在 unhook 之后误调用 append,会直接抛运行时异常。建议让 unhook/append 在已 unhook 状态下幂等(例如 unhooks 为 null 时直接 return),并把 unhooks 的函数类型收敛为 () => void,减少 any 带来的误用。
| private unhooks: ((...args: any) => any)[] | null = []; | |
| public append(...fns: ((...args: any) => any)[]) { | |
| this.unhooks!.push(...fns); | |
| } | |
| public readonly unhook = () => { | |
| this.isMounted = false; | |
| for (const unhook of this.unhooks!) unhook(); | |
| this.unhooks!.length = 0; | |
| // 存储卸载时调用的钩子函数;unhook 后置为 null | |
| private unhooks: (() => void)[] | null = []; | |
| public append(...fns: (() => void)[]) { | |
| // 已经 unhook 的情况下保持幂等,直接忽略追加 | |
| if (!this.unhooks) return; | |
| this.unhooks.push(...fns); | |
| } | |
| public readonly unhook = () => { | |
| // 已经 unhook 过则保持幂等 | |
| if (!this.unhooks) return; | |
| this.isMounted = false; | |
| for (const unhook of this.unhooks) { | |
| unhook(); | |
| } | |
| this.unhooks.length = 0; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
雖然好像沒必要。但小心為上吧
80b1378
| @@ -0,0 +1,13 @@ | |||
| export class HookManager { | |||
Copilot
AI
Feb 12, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
文件名 hookManger.ts 似乎是 HookManager 的拼写误差(少了 a),且与类名不一致,后续检索/导入时容易踩坑。建议尽早统一为 hookManager.ts(或按 utils 目录既有命名风格改为 hook_manager.ts),并同步更新所有 import 路径。
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
呀! 打錯字了!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
| const hookMgr = new HookManager(); | ||
| hookMgr.append(subscribeMessage<ThemeParam>("onColorThemeUpdated", pageApi.onColorThemeUpdated)); | ||
|
|
||
| return hookMgr.unhook; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
就一个subscribe,为了统一的话,问题不大
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
- 统一写法
- 主要是用来避开 closure GC 问题
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
- 主要是用来避开 closure GC 问题
实例化一个HookManager可比closure GC开销大多了
src/pages/store/global.ts
Outdated
| export const subscribeMessage = <T extends object>(topic: string, handler: (msg: T) => void) => { | ||
| return messageQueue.subscribe<T & { myMessage?: T }>(topic, (data) => { | ||
| const message = data?.myMessage || data; | ||
| if (typeof message === "object") { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@CodFrm 这个改 if (message && typeof message === "object") { 是避免 message 是 null 的问题。不过没所谓。不改也行。
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
这个myMessage是做啥的来着,感觉也没什么地方用,也没必要用?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
onScriptUpdateCheck 有用到
当初怕跟其他 message 消息传递冲突,做了一个新名字
先这样保留名字吧。日后可以再另外PR
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
挺奇怪的,那就日后再说吧
2e53baf to
f4da477
Compare
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>