fix: patch memory leaks in event hooks and strengthen type guard
Fix three bugs found during code review: 1. useTauriEvent/useTauriEvents: If the component unmounts before the async listen() promise resolves, the unlisten function was lost, leaking the event subscription. Added a cancelled flag to call unlisten immediately when the promise resolves after cleanup. 2. useTauriEvents: The handlers object was used directly as a useEffect dependency, causing re-subscription on every render when callers pass an inline object literal. Replaced with a useRef for handler stability and a derived eventNames string as the dependency. 3. isMcError type guard: Only checked property existence via 'in' operator, not property types. An object with wrong-typed properties (e.g. code: 42) would pass the guard. Now validates that code and message are strings and recoverable is boolean. 4. AppShell global shortcut listener: Same race condition as (1), plus missing .catch() on the listen promise could produce unhandled rejections. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -38,14 +38,30 @@ export function AppShell(): React.ReactElement {
|
||||
|
||||
// Listen for global shortcut events from the Rust backend
|
||||
useEffect(() => {
|
||||
const unlisten = listen<string>("global-shortcut-triggered", (event) => {
|
||||
let cancelled = false;
|
||||
let unlisten: (() => void) | undefined;
|
||||
|
||||
listen<string>("global-shortcut-triggered", (event) => {
|
||||
if (event.payload === "quick-capture") {
|
||||
useCaptureStore.getState().open();
|
||||
}
|
||||
});
|
||||
})
|
||||
.then((fn) => {
|
||||
if (cancelled) {
|
||||
fn();
|
||||
} else {
|
||||
unlisten = fn;
|
||||
}
|
||||
})
|
||||
.catch((err: unknown) => {
|
||||
console.warn("[AppShell] Failed to subscribe to global shortcut:", err);
|
||||
});
|
||||
|
||||
return () => {
|
||||
unlisten.then((fn) => fn());
|
||||
cancelled = true;
|
||||
if (unlisten) {
|
||||
unlisten();
|
||||
}
|
||||
};
|
||||
}, []);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user