diff --git a/.changeset/bumpy-cycles-carry.md b/.changeset/bumpy-cycles-carry.md new file mode 100644 index 00000000000..7ec028b394a --- /dev/null +++ b/.changeset/bumpy-cycles-carry.md @@ -0,0 +1,9 @@ +--- +'eslint-plugin-qwik': patch +'create-qwik': patch +'@builder.io/qwik-react': patch +'@builder.io/qwik-city': patch +'@builder.io/qwik': patch +--- + +execute cleanup cb for all component tree while calling dispose.cleanup method returned by render fn diff --git a/packages/qwik/src/core/render/dom/render.public.ts b/packages/qwik/src/core/render/dom/render.public.ts index 27ecd32ba09..c4d875cf254 100644 --- a/packages/qwik/src/core/render/dom/render.public.ts +++ b/packages/qwik/src/core/render/dom/render.public.ts @@ -124,7 +124,7 @@ export const injectQContainer = (containerEl: Element) => { function cleanupContainer(renderCtx: RenderContext, container: Element) { const subsManager = renderCtx.$static$.$containerState$.$subsManager$; - cleanupTree(container, renderCtx.$static$, subsManager, true); + cleanupTree(container, renderCtx.$static$, subsManager, true, true); removeContainerState(container); diff --git a/packages/qwik/src/core/render/dom/render.unit.tsx b/packages/qwik/src/core/render/dom/render.unit.tsx index bf89c3dd977..60fc11825a1 100644 --- a/packages/qwik/src/core/render/dom/render.unit.tsx +++ b/packages/qwik/src/core/render/dom/render.unit.tsx @@ -778,14 +778,37 @@ test('should clean up subscriptions after calling the returned cleanup function' const fixture = new ElementFixture(); const spies = { - cleanupSpy: false, + cleanup: false, }; const { cleanup } = await render(fixture.host, ); cleanup(); - assert.equal(spies.cleanupSpy, true); + assert.equal(spies.cleanup, true); +}); + +test('should clean up nested subscriptions after calling the returned cleanup function', async () => { + const fixture = new ElementFixture(); + + const spies = { + parentCleanup: false, + cleanup: false, + slottedCleanup: false, + }; + + const { cleanup } = await render( + fixture.host, + + + + ); + + cleanup(); + + assert.equal(spies.parentCleanup, true); + assert.equal(spies.cleanup, true); + assert.equal(spies.slottedCleanup, true); }); async function expectRendered(fixture: ElementFixture, expected: string) { @@ -1045,16 +1068,56 @@ export const Hooks = component$(() => { ////////////////////////////////////////////////////////////////////////////////////////// -export const CleanupComponent = component$((props: { spies: { cleanupSpy: boolean } }) => { +interface CleanupProps { + spies: { + parentCleanup?: boolean; + cleanup?: boolean; + slottedCleanup?: boolean; + }; +} + +export const ParentCleanupComponent = component$((props: CleanupProps) => { useTask$(({ cleanup }) => { cleanup(() => { - props.spies.cleanupSpy = true; + props.spies.parentCleanup = true; + }); + }); + + return ( +
+
true
+ + + +
+ ); +}); + +export const CleanupComponent = component$((props: CleanupProps) => { + useTask$(({ cleanup }) => { + cleanup(() => { + props.spies.cleanup = true; }); }); return (
true
+ +
+ ); +}); + +export const SlottedCleanupComponent = component$((props: CleanupProps) => { + useTask$(({ cleanup }) => { + cleanup(() => { + props.spies.slottedCleanup = true; + }); + }); + + return ( +
+
true
); }); diff --git a/packages/qwik/src/core/render/dom/visitor.ts b/packages/qwik/src/core/render/dom/visitor.ts index 401749980ba..e7ff49f4bf4 100644 --- a/packages/qwik/src/core/render/dom/visitor.ts +++ b/packages/qwik/src/core/render/dom/visitor.ts @@ -1135,11 +1135,12 @@ export const cleanupTree = ( elm: Node | VirtualElement, staticCtx: RenderStaticContext, subsManager: SubscriptionManager, - stopSlots: boolean + stopSlots: boolean, + dispose = false ) => { subsManager.$clearSub$(elm); if (isQwikElement(elm)) { - if (stopSlots && elm.hasAttribute(QSlotS)) { + if (!dispose && stopSlots && elm.hasAttribute(QSlotS)) { staticCtx.$rmSlots$.push(elm); return; } @@ -1150,7 +1151,7 @@ export const cleanupTree = ( const end = isVirtualElement(elm) ? elm.close : null; let node: Node | null | VirtualElement = elm.firstChild; while ((node = processVirtualNodes(node))) { - cleanupTree(node!, staticCtx, subsManager, true); + cleanupTree(node!, staticCtx, subsManager, true, dispose); node = node.nextSibling; if (node === end) { break; diff --git a/starters/apps/starter-partytown-test/src/root.tsx b/starters/apps/starter-partytown-test/src/root.tsx index 72ce5c7d1e9..801a3fcfb96 100644 --- a/starters/apps/starter-partytown-test/src/root.tsx +++ b/starters/apps/starter-partytown-test/src/root.tsx @@ -9,7 +9,12 @@ export default () => { Qwik + Partytown Blank App -