mirror of
				https://github.com/zadam/trilium.git
				synced 2025-10-31 10:26:08 +01:00 
			
		
		
		
	fix(react/settings): useTriliumEvent not cleaning up properly
This commit is contained in:
		| @@ -5,7 +5,10 @@ import SpacedUpdate from "../../services/spaced_update"; | ||||
| import { OptionNames } from "@triliumnext/commons"; | ||||
| import options from "../../services/options"; | ||||
| import utils, { reloadFrontendApp } from "../../services/utils"; | ||||
| import { __values } from "tslib"; | ||||
| import Component from "../../components/component"; | ||||
|  | ||||
| type TriliumEventHandler<T extends EventNames> = (data: EventData<T>) => void; | ||||
| const registeredHandlers: Map<Component, Map<EventNames, TriliumEventHandler<any>[]>> = new Map(); | ||||
|  | ||||
| /** | ||||
|  * Allows a React component to react to Trilium events (e.g. `entitiesReloaded`). When the desired event is triggered, the handler is invoked with the event parameters. | ||||
| @@ -16,32 +19,59 @@ import { __values } from "tslib"; | ||||
|  * @param handler the handler to be invoked when the event is triggered. | ||||
|  * @param enabled determines whether the event should be listened to or not. Useful to conditionally limit the listener based on a state (e.g. a modal being displayed). | ||||
|  */ | ||||
| export default function useTriliumEvent<T extends EventNames>(eventName: T, handler: (data: EventData<T>) => void, enabled = true) { | ||||
| export default function useTriliumEvent<T extends EventNames>(eventName: T, handler: TriliumEventHandler<T>, enabled = true) { | ||||
|     const parentWidget = useContext(ParentComponent); | ||||
|     useEffect(() => { | ||||
|         if (!parentWidget || !enabled) {             | ||||
|     if (!parentWidget) { | ||||
|         return; | ||||
|     } | ||||
|      | ||||
|         // Create a unique handler name for this specific event listener | ||||
|     const handlerName = `${eventName}Event`; | ||||
|         const originalHandler = parentWidget[handlerName]; | ||||
|  | ||||
|         // Override the event handler to call our handler | ||||
|         parentWidget[handlerName] = async function(data: EventData<T>) { | ||||
|             // Call original handler if it exists | ||||
|             if (originalHandler) { | ||||
|                 await originalHandler.call(parentWidget, data); | ||||
|     const customHandler  = useMemo(() => { | ||||
|         return async (data: EventData<T>) => { | ||||
|             // Inform the attached event listeners. | ||||
|             const eventHandlers = registeredHandlers.get(parentWidget)?.get(eventName) ?? []; | ||||
|             for (const eventHandler of eventHandlers) { | ||||
|                 eventHandler(data); | ||||
|             } | ||||
|             // Call our React component's handler | ||||
|             handler(data); | ||||
|         }; | ||||
|         } | ||||
|     }, [ eventName, parentWidget ]);     | ||||
|  | ||||
|     useEffect(() => { | ||||
|         // Attach to the list of handlers. | ||||
|         let handlersByWidget = registeredHandlers.get(parentWidget); | ||||
|         if (!handlersByWidget) { | ||||
|             handlersByWidget = new Map(); | ||||
|             registeredHandlers.set(parentWidget, handlersByWidget); | ||||
|         } | ||||
|  | ||||
|         let handlersByWidgetAndEventName = handlersByWidget.get(eventName); | ||||
|         if (!handlersByWidgetAndEventName) { | ||||
|             handlersByWidgetAndEventName = []; | ||||
|             handlersByWidget.set(eventName, handlersByWidgetAndEventName); | ||||
|         } | ||||
|  | ||||
|         if (!handlersByWidgetAndEventName.includes(handler)) { | ||||
|             handlersByWidgetAndEventName.push(handler); | ||||
|         } | ||||
|  | ||||
|         // Apply the custom event handler. | ||||
|         if (parentWidget[handlerName] && parentWidget[handlerName] !== customHandler) { | ||||
|             console.warn(`Widget ${parentWidget.componentId} already had an event listener and it was replaced by the React one.`); | ||||
|         } | ||||
|          | ||||
|         parentWidget[handlerName] = customHandler; | ||||
|      | ||||
|         // Cleanup: restore original handler on unmount or when disabled | ||||
|         return () => { | ||||
|             parentWidget[handlerName] = originalHandler; | ||||
|             const eventHandlers = registeredHandlers.get(parentWidget)?.get(eventName); | ||||
|             if (!eventHandlers || !eventHandlers.includes(handler)) { | ||||
|                 return; | ||||
|             } | ||||
|      | ||||
|             // Remove the event handler from the array. | ||||
|             const newEventHandlers = eventHandlers.filter(e => e !== handler); | ||||
|             registeredHandlers.get(parentWidget)?.set(eventName, newEventHandlers);         | ||||
|         }; | ||||
|     }, [parentWidget, enabled, eventName, handler]); | ||||
|     }, [ eventName, parentWidget, handler ]); | ||||
| } | ||||
|  | ||||
| export function useSpacedUpdate(callback: () => Promise<void>, interval = 1000) { | ||||
|   | ||||
| @@ -74,12 +74,14 @@ const FONT_FAMILIES: FontGroup[] = [ | ||||
| ]; | ||||
|  | ||||
| export default function AppearanceSettings() {     | ||||
|     const [ overrideThemeFonts ] = useTriliumOption("overrideThemeFonts"); | ||||
|  | ||||
|     return ( | ||||
|         <> | ||||
|         <div> | ||||
|             <LayoutOrientation /> | ||||
|             <ApplicationTheme /> | ||||
|             <Fonts /> | ||||
|         </> | ||||
|             {overrideThemeFonts === "true" && <Fonts />} | ||||
|         </div> | ||||
|     ) | ||||
| } | ||||
|  | ||||
|   | ||||
		Reference in New Issue
	
	Block a user