Skip to content

Commit 36008d4

Browse files
committed
chore: 优化代码写法
1 parent beaca21 commit 36008d4

3 files changed

Lines changed: 56 additions & 20 deletions

File tree

app/src/core/extension/Extension.tsx

Lines changed: 12 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -167,20 +167,8 @@ export class Extension extends Tab {
167167
const [installed, setInstalled] = useState(false);
168168
const [disabledExtensions, setDisabledExtensions] = Settings.use("disabledExtensions");
169169
const disabled = disabledExtensions.includes(self.metadata.extension?.id || "");
170-
// 响应式快捷键列表:订阅 KeyBindsUI 的变化,安装插件后自动刷新
171-
const [extensionKeyBinds, setExtensionKeyBinds] = useState(() => {
172-
const prefix = `ext:${self.metadata.extension?.id || ""}:`;
173-
return KeyBindsUI.getAllUIKeyBinds().filter((kb) => kb.id.startsWith(prefix));
174-
});
175-
176-
useEffect(() => {
177-
const extensionId = self.metadata.extension?.id || "";
178-
const prefix = `ext:${extensionId}:`;
179-
const unsubscribe = KeyBindsUI.onKeyBindListChange((allBinds) => {
180-
setExtensionKeyBinds(allBinds.filter((kb) => kb.id.startsWith(prefix)));
181-
});
182-
return unsubscribe;
183-
}, []);
170+
// 响应式快捷键列表:安装插件后自动刷新
171+
const extensionKeyBinds = KeyBindsUI.use((kb) => kb.id.startsWith(`ext:${self.metadata.extension?.id || ""}:`));
184172

185173
useEffect(() => {
186174
(async () => {
@@ -219,11 +207,12 @@ export class Extension extends Tab {
219207
variant="outline"
220208
onClick={async () => {
221209
if (await Dialog.confirm("确认卸载", "将彻底删除此扩展,无法恢复。请确认是否继续。")) {
222-
ExtensionKeyBindManager.unregisterAll(self.metadata.extension?.id || "");
223-
await self.fs.remove(
224-
URI.file(await join(await appDataDir(), "extensions", self.metadata.extension?.id || "")),
225-
);
226-
setDisabledExtensions(disabledExtensions.filter((id) => id !== self.metadata.extension?.id));
210+
const extId = self.metadata.extension?.id || "";
211+
ExtensionKeyBindManager.unregisterAll(extId);
212+
// 终止 Worker 并清除缓存,使重新安装时能创建新 Runtime
213+
ExtensionManager.unload(extId);
214+
await self.fs.remove(URI.file(await join(await appDataDir(), "extensions", extId)));
215+
setDisabledExtensions(disabledExtensions.filter((id) => id !== extId));
227216
setInstalled(false);
228217
toast.success("扩展已卸载");
229218
}
@@ -281,7 +270,10 @@ export class Extension extends Tab {
281270
await writeFile(await join(base, self.iconFileName), self.iconRawData);
282271
}
283272
// 安装完成后立即运行插件,使其快捷键等功能即时生效,无需重载
284-
await ExtensionManager.getRuntime(self.metadata.extension?.id || "unknown");
273+
// 先 unload 清除可能残留的旧缓存,再创建新 Runtime
274+
const extId = self.metadata.extension?.id || "unknown";
275+
ExtensionManager.unload(extId);
276+
await ExtensionManager.getRuntime(extId);
285277
setInstalled(true);
286278
toast.success("扩展已安装");
287279
}}

app/src/core/extension/ExtensionManager.tsx

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,18 @@ export namespace ExtensionManager {
4444
return runtime;
4545
}
4646

47+
/**
48+
* 卸载单个扩展:终止 Worker 并清除缓存,使下次 getRuntime 能重新创建
49+
*/
50+
export function unload(name: string) {
51+
const runtime = runtimes.get(name);
52+
if (runtime) {
53+
runtime.terminate();
54+
runtimes.delete(name);
55+
}
56+
extensions.delete(name);
57+
}
58+
4759
/**
4860
* 创建并运行所有扩展
4961
*/

app/src/core/service/controlService/shortcutKeysEngine/KeyBindsUI.tsx

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import { createStore } from "@/utils/store";
1212
import { Queue } from "@graphif/data-structures";
1313
import { proxy } from "comlink";
1414
import type { ForwardRefExoticComponent, RefAttributes } from "react";
15+
import { useEffect, useState } from "react";
1516
import type { LucideProps } from "lucide-react";
1617
import { allKeyBinds, type KeyBindWhen } from "./shortcutKeysRegister";
1718

@@ -68,6 +69,8 @@ export namespace KeyBindsUI {
6869
*/
6970
export function onKeyBindListChange(callback: (keyBinds: UIKeyBind[]) => void): () => void {
7071
keyBindListChangeListeners.add(callback);
72+
// 立即以当前状态回调一次,确保订阅者拿到最新值(BehaviorSubject 语义)
73+
callback([...allUIKeyBinds]);
7174
return () => {
7275
keyBindListChangeListeners.delete(callback);
7376
};
@@ -82,6 +85,35 @@ export namespace KeyBindsUI {
8285
});
8386
}
8487

88+
/**
89+
* React Hook:订阅快捷键列表,返回经过 filter 过滤后的响应式列表。
90+
* 列表发生变化时组件自动重渲染。
91+
*
92+
* @param filter 可选过滤函数,默认返回全部快捷键
93+
* @example
94+
* // 获取所有快捷键
95+
* const binds = KeyBindsUI.use();
96+
* // 只获取某个插件的快捷键
97+
* const binds = KeyBindsUI.use((kb) => kb.id.startsWith("ext:my-ext:"));
98+
*/
99+
export function use(filter?: (kb: UIKeyBind) => boolean): UIKeyBind[] {
100+
// 初始值同步计算,避免首次渲染闪烁
101+
const [binds, setBinds] = useState<UIKeyBind[]>(() => {
102+
const all = getAllUIKeyBinds();
103+
return filter ? all.filter(filter) : all;
104+
});
105+
106+
useEffect(() => {
107+
// 订阅后续变化;onKeyBindListChange 也会立即回调一次同步当前值,
108+
// 确保 useEffect 执行时若列表已更新也能正确反映
109+
return onKeyBindListChange((all) => {
110+
setBinds(filter ? all.filter(filter) : all);
111+
});
112+
}, []); // filter 是调用方传入的内联箭头函数,不应放入依赖数组
113+
114+
return binds;
115+
}
116+
85117
// 快捷键变化监听器
86118
const keyBindChangeListeners = new Map<string, Set<(keyBind: UIKeyBind) => void>>();
87119

0 commit comments

Comments
 (0)