From 57782aa786b89388c0ce265942cbbddf5c3fe3ff Mon Sep 17 00:00:00 2001 From: "Stephane Vanmeerhaeghe (stva)" Date: Thu, 29 Jan 2026 16:46:59 +0100 Subject: [PATCH] [FIX] reactivity: fix memory leak Ensure proper garbage collection of the component when async methods finish after component destruction. --- src/runtime/component_node.ts | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/src/runtime/component_node.ts b/src/runtime/component_node.ts index 31d4d9330..517e3fd02 100644 --- a/src/runtime/component_node.ts +++ b/src/runtime/component_node.ts @@ -55,16 +55,23 @@ const batchedRenderFunctions = new WeakMap(); */ export function useState(state: T): T { const node = getCurrent(); - let render = batchedRenderFunctions.get(node)!; + let render = batchedRenderFunctions.get(node); if (!render) { - render = batched(node.render.bind(node, false)); + const wrapper = { fn: batched(node.render.bind(node, false)) }; + render = (...args) => wrapper.fn(...args); batchedRenderFunctions.set(node, render); // manual implementation of onWillDestroy to break cyclic dependency - node.willDestroy.push(clearReactivesForCallback.bind(null, render)); + node.willDestroy.push(cleanupRenderAndReactives.bind(null, wrapper, render)); } return reactive(state, render); } +const NO_OP = () => {}; +function cleanupRenderAndReactives(wrapper: any, render: Callback) { + wrapper.fn = NO_OP; + clearReactivesForCallback(render); +} + // ----------------------------------------------------------------------------- // Component VNode class // -----------------------------------------------------------------------------