From 72b2a5cc0d37c21388f5fd15aaf98c7269f65e0d Mon Sep 17 00:00:00 2001 From: Elian Doran Date: Mon, 25 Aug 2025 14:27:32 +0300 Subject: [PATCH] chore(react): use effects for event handlers to prevent leaks --- apps/client/src/widgets/react/hooks.tsx | 61 +++++++++++++++---------- 1 file changed, 36 insertions(+), 25 deletions(-) diff --git a/apps/client/src/widgets/react/hooks.tsx b/apps/client/src/widgets/react/hooks.tsx index 483f826dd..b0fbacfa4 100644 --- a/apps/client/src/widgets/react/hooks.tsx +++ b/apps/client/src/widgets/react/hooks.tsx @@ -17,31 +17,35 @@ import { CSSProperties } from "preact/compat"; export function useTriliumEvent(eventName: T, handler: (data: EventData) => void) { const parentComponent = useContext(ParentComponent)!; - parentComponent.registerHandler(eventName, handler); + useEffect(() => { + parentComponent.registerHandler(eventName, handler); + return (() => parentComponent.removeHandler(eventName, handler)); + }, []); useDebugValue(eventName); - return (() => parentComponent.removeHandler(eventName, handler)); } export function useTriliumEvents(eventNames: T[], handler: (data: EventData, eventName: T) => void) { const parentComponent = useContext(ParentComponent)!; - const handlers: ({ eventName: T, callback: (data: EventData) => void })[] = []; - useDebugValue(() => eventNames.join(", ")); - - for (const eventName of eventNames) { - handlers.push({ eventName, callback: (data) => { - handler(data, eventName); - }}) - } - - for (const { eventName, callback } of handlers) { - parentComponent.registerHandler(eventName, callback); - } - - return (() => { - for (const { eventName, callback } of handlers) { - parentComponent.removeHandler(eventName, callback); + + useEffect(() => { + const handlers: ({ eventName: T, callback: (data: EventData) => void })[] = []; + for (const eventName of eventNames) { + handlers.push({ eventName, callback: (data) => { + handler(data, eventName); + }}) } - }); + + for (const { eventName, callback } of handlers) { + parentComponent.registerHandler(eventName, callback); + } + + return (() => { + for (const { eventName, callback } of handlers) { + parentComponent.removeHandler(eventName, callback); + } + }); + }, []); + useDebugValue(() => eventNames.join(", ")); } export function useSpacedUpdate(callback: () => void | Promise, interval = 1000) { @@ -202,9 +206,6 @@ export function useNoteContext() { setNoteContext(noteContext); setNotePath(noteContext.notePath); }); - useTriliumEvent("setNoteContext", ({ noteContext }) => { - setNoteContext(noteContext); - }); useTriliumEvent("noteSwitchedAndActivated", ({ noteContext }) => { setNoteContext(noteContext); }); @@ -215,6 +216,12 @@ export function useNoteContext() { setNote(noteContext?.note); }); + useLegacyImperativeHandlers({ + setNoteContextEvent({ noteContext }: EventData<"setNoteContext">) { + setNoteContext(noteContext); + } + }, true); + useDebugValue(() => `notePath=${notePath}, ntxId=${noteContext?.ntxId}`); const parentComponent = useContext(ParentComponent) as ReactWrappedWidget; @@ -506,9 +513,13 @@ export function useTooltip(elRef: RefObject, config: Partial) { +export function useLegacyImperativeHandlers(handlers: Record, force?: boolean) { const parentComponent = useContext(ParentComponent); - useEffect(() => { + if (!force) { + useEffect(() => { + Object.assign(parentComponent as any, handlers); + }, [ handlers ]) + } else { Object.assign(parentComponent as any, handlers); - }, [ handlers ]) + } } \ No newline at end of file