mirror of
				https://github.com/zadam/trilium.git
				synced 2025-10-30 02:59:03 +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); | ||||||
|  | } | ||||||
| @ -68,9 +68,17 @@ export default function useTriliumEvent<T extends EventNames>(eventName: T, hand | |||||||
|                 return; |                 return; | ||||||
|             } |             } | ||||||
|      |      | ||||||
|             // 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
	 Elian Doran
						Elian Doran