mirror of
https://github.com/zadam/trilium.git
synced 2025-10-21 15:49:00 +02:00
fix(react/settings): useTriliumEvent not cleaning up properly
This commit is contained in:
parent
e7b448e2bc
commit
2793df06c4
@ -5,7 +5,10 @@ import SpacedUpdate from "../../services/spaced_update";
|
|||||||
import { OptionNames } from "@triliumnext/commons";
|
import { OptionNames } from "@triliumnext/commons";
|
||||||
import options from "../../services/options";
|
import options from "../../services/options";
|
||||||
import utils, { reloadFrontendApp } from "../../services/utils";
|
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.
|
* 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 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).
|
* @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);
|
const parentWidget = useContext(ParentComponent);
|
||||||
useEffect(() => {
|
if (!parentWidget) {
|
||||||
if (!parentWidget || !enabled) {
|
return;
|
||||||
return;
|
}
|
||||||
}
|
|
||||||
|
const handlerName = `${eventName}Event`;
|
||||||
// Create a unique handler name for this specific event listener
|
const customHandler = useMemo(() => {
|
||||||
const handlerName = `${eventName}Event`;
|
return async (data: EventData<T>) => {
|
||||||
const originalHandler = parentWidget[handlerName];
|
// Inform the attached event listeners.
|
||||||
|
const eventHandlers = registeredHandlers.get(parentWidget)?.get(eventName) ?? [];
|
||||||
// Override the event handler to call our handler
|
for (const eventHandler of eventHandlers) {
|
||||||
parentWidget[handlerName] = async function(data: EventData<T>) {
|
eventHandler(data);
|
||||||
// Call original handler if it exists
|
|
||||||
if (originalHandler) {
|
|
||||||
await originalHandler.call(parentWidget, data);
|
|
||||||
}
|
}
|
||||||
// Call our React component's handler
|
}
|
||||||
handler(data);
|
}, [ eventName, parentWidget ]);
|
||||||
};
|
|
||||||
|
|
||||||
// Cleanup: restore original handler on unmount or when disabled
|
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;
|
||||||
|
|
||||||
return () => {
|
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) {
|
export function useSpacedUpdate(callback: () => Promise<void>, interval = 1000) {
|
||||||
|
@ -74,12 +74,14 @@ const FONT_FAMILIES: FontGroup[] = [
|
|||||||
];
|
];
|
||||||
|
|
||||||
export default function AppearanceSettings() {
|
export default function AppearanceSettings() {
|
||||||
|
const [ overrideThemeFonts ] = useTriliumOption("overrideThemeFonts");
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<div>
|
||||||
<LayoutOrientation />
|
<LayoutOrientation />
|
||||||
<ApplicationTheme />
|
<ApplicationTheme />
|
||||||
<Fonts />
|
{overrideThemeFonts === "true" && <Fonts />}
|
||||||
</>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -141,7 +143,7 @@ function ApplicationTheme() {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
function Fonts() {
|
function Fonts() {
|
||||||
return (
|
return (
|
||||||
<OptionsSection title={t("fonts.fonts")}>
|
<OptionsSection title={t("fonts.fonts")}>
|
||||||
<Font title={t("fonts.main_font")} fontFamilyOption="mainFontFamily" />
|
<Font title={t("fonts.main_font")} fontFamilyOption="mainFontFamily" />
|
||||||
|
Loading…
x
Reference in New Issue
Block a user