mirror of
https://github.com/zadam/trilium.git
synced 2025-10-30 11:09:05 +01:00
fix(react/settings): hook leak after closing tabs
This commit is contained in:
parent
3837466cb3
commit
73ff41f2b2
@ -2,6 +2,7 @@ import FlexContainer from "./flex_container.js";
|
|||||||
import appContext, { type CommandData, type CommandListenerData, type EventData, type EventNames, type NoteSwitchedContext } from "../../components/app_context.js";
|
import appContext, { type CommandData, type CommandListenerData, type EventData, type EventNames, type NoteSwitchedContext } from "../../components/app_context.js";
|
||||||
import type BasicWidget from "../basic_widget.js";
|
import type BasicWidget from "../basic_widget.js";
|
||||||
import type NoteContext from "../../components/note_context.js";
|
import type NoteContext from "../../components/note_context.js";
|
||||||
|
import Component from "../../components/component.js";
|
||||||
|
|
||||||
interface NoteContextEvent {
|
interface NoteContextEvent {
|
||||||
noteContext: NoteContext;
|
noteContext: NoteContext;
|
||||||
@ -152,6 +153,8 @@ export default class SplitNoteContainer extends FlexContainer<SplitNoteWidget> {
|
|||||||
for (const ntxId of ntxIds) {
|
for (const ntxId of ntxIds) {
|
||||||
this.$widget.find(`[data-ntx-id="${ntxId}"]`).remove();
|
this.$widget.find(`[data-ntx-id="${ntxId}"]`).remove();
|
||||||
|
|
||||||
|
const widget = this.widgets[ntxId];
|
||||||
|
recursiveCleanup(widget);
|
||||||
delete this.widgets[ntxId];
|
delete this.widgets[ntxId];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -237,3 +240,12 @@ export default class SplitNoteContainer extends FlexContainer<SplitNoteWidget> {
|
|||||||
return Promise.all(promises);
|
return Promise.all(promises);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function recursiveCleanup(widget: Component) {
|
||||||
|
for (const child of widget.children) {
|
||||||
|
recursiveCleanup(child);
|
||||||
|
}
|
||||||
|
if ("cleanup" in widget && typeof widget.cleanup === "function") {
|
||||||
|
widget.cleanup();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@ -22,11 +22,18 @@ export default abstract class ReactBasicWidget extends BasicWidget {
|
|||||||
* @returns the rendered wrapped DOM element.
|
* @returns the rendered wrapped DOM element.
|
||||||
*/
|
*/
|
||||||
export function renderReactWidget(parentComponent: Component, el: JSX.Element) {
|
export function renderReactWidget(parentComponent: Component, el: JSX.Element) {
|
||||||
const renderContainer = new DocumentFragment();
|
return renderReactWidgetAtElement(parentComponent, el, new DocumentFragment()).children();
|
||||||
|
}
|
||||||
|
|
||||||
|
export function renderReactWidgetAtElement(parentComponent: Component, el: JSX.Element, container: Element | DocumentFragment) {
|
||||||
render((
|
render((
|
||||||
<ParentComponent.Provider value={parentComponent}>
|
<ParentComponent.Provider value={parentComponent}>
|
||||||
{el}
|
{el}
|
||||||
</ParentComponent.Provider>
|
</ParentComponent.Provider>
|
||||||
), renderContainer);
|
), container);
|
||||||
return $(renderContainer.children) as JQuery<HTMLElement>;
|
return $(container) as JQuery<HTMLElement>;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function disposeReactWidget(container: Element) {
|
||||||
|
render(null, container);
|
||||||
}
|
}
|
||||||
@ -70,7 +70,15 @@ export default function useTriliumEvent<T extends EventNames>(eventName: T, hand
|
|||||||
|
|
||||||
// Remove the event handler from the array.
|
// Remove the event handler from the array.
|
||||||
const newEventHandlers = eventHandlers.filter(e => e !== handler);
|
const newEventHandlers = eventHandlers.filter(e => e !== handler);
|
||||||
registeredHandlers.get(parentWidget)?.set(eventName, newEventHandlers);
|
if (newEventHandlers.length) {
|
||||||
|
registeredHandlers.get(parentWidget)?.set(eventName, newEventHandlers);
|
||||||
|
} else {
|
||||||
|
registeredHandlers.get(parentWidget)?.delete(eventName);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!registeredHandlers.get(parentWidget)?.size) {
|
||||||
|
registeredHandlers.delete(parentWidget);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
}, [ eventName, parentWidget, handler ]);
|
}, [ eventName, parentWidget, handler ]);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -7,7 +7,7 @@ import { t } from "../../services/i18n.js";
|
|||||||
import type BasicWidget from "../basic_widget.js";
|
import type BasicWidget from "../basic_widget.js";
|
||||||
import type { JSX } from "preact/jsx-runtime";
|
import type { JSX } from "preact/jsx-runtime";
|
||||||
import AppearanceSettings from "./options/appearance.jsx";
|
import AppearanceSettings from "./options/appearance.jsx";
|
||||||
import { renderReactWidget } from "../react/ReactBasicWidget.jsx";
|
import { disposeReactWidget, renderReactWidget, renderReactWidgetAtElement } from "../react/ReactBasicWidget.jsx";
|
||||||
import ImageSettings from "./options/images.jsx";
|
import ImageSettings from "./options/images.jsx";
|
||||||
import AdvancedSettings from "./options/advanced.jsx";
|
import AdvancedSettings from "./options/advanced.jsx";
|
||||||
import InternationalizationOptions from "./options/i18n.jsx";
|
import InternationalizationOptions from "./options/i18n.jsx";
|
||||||
@ -21,6 +21,7 @@ import TextNoteSettings from "./options/text_notes.jsx";
|
|||||||
import CodeNoteSettings from "./options/code_notes.jsx";
|
import CodeNoteSettings from "./options/code_notes.jsx";
|
||||||
import OtherSettings from "./options/other.jsx";
|
import OtherSettings from "./options/other.jsx";
|
||||||
import BackendLogWidget from "./content/backend_log.js";
|
import BackendLogWidget from "./content/backend_log.js";
|
||||||
|
import { unmountComponentAtNode } from "preact/compat";
|
||||||
|
|
||||||
const TPL = /*html*/`<div class="note-detail-content-widget note-detail-printable">
|
const TPL = /*html*/`<div class="note-detail-content-widget note-detail-printable">
|
||||||
<style>
|
<style>
|
||||||
@ -120,7 +121,18 @@ export default class ContentWidgetTypeWidget extends TypeWidget {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// React widget.
|
// React widget.
|
||||||
this.$content.append(renderReactWidget(this, contentWidgets));
|
renderReactWidgetAtElement(this, contentWidgets, this.$content[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
cleanup(): void {
|
||||||
|
if (this.noteId) {
|
||||||
|
const contentWidgets = (CONTENT_WIDGETS as Record<string, (typeof NoteContextAwareWidget[] | JSX.Element)>)[this.noteId];
|
||||||
|
if (contentWidgets && !Array.isArray(contentWidgets)) {
|
||||||
|
disposeReactWidget(this.$content[0]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
super.cleanup();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -101,4 +101,8 @@ export default abstract class TypeWidget extends NoteContextAwareWidget {
|
|||||||
return Promise.resolve();
|
return Promise.resolve();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
cleanup(): void {
|
||||||
|
super.cleanup();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user