From ec71d337be35ed2e9fd0bf6da6b13317238636e3 Mon Sep 17 00:00:00 2001 From: kasperskei Date: Fri, 27 Sep 2024 13:34:06 +0300 Subject: [PATCH] fix(jsx): unsubscribe when removing a parent element (#919) --- package-lock.json | 10 +++++----- package.json | 2 +- packages/jsx/package.json | 2 +- packages/jsx/src/index.test.tsx | 3 ++- packages/jsx/src/index.ts | 18 ++++++++++++------ 5 files changed, 21 insertions(+), 14 deletions(-) diff --git a/package-lock.json b/package-lock.json index 310a5153f..ee550b9bd 100644 --- a/package-lock.json +++ b/package-lock.json @@ -24,7 +24,7 @@ "core-js": "^3.37.1", "history": "^5.3.0", "husky": "^8.0.3 ", - "linkedom": "^0.16.10", + "linkedom": "^0.18.5", "lit": "^3.1.2", "microbundle": "^0.15.1", "react": "^18.2.0", @@ -7110,9 +7110,9 @@ "dev": true }, "node_modules/linkedom": { - "version": "0.16.10", - "resolved": "https://registry.npmjs.org/linkedom/-/linkedom-0.16.10.tgz", - "integrity": "sha512-c316CX1FiPMU1v4+ExUzxr/gD5xqyCX2M3qtyL2nuoYQTsk0F5jRRwOFG7jRRxD3w7ONbLTLMrGBvq++Hmzzhg==", + "version": "0.18.5", + "resolved": "https://registry.npmjs.org/linkedom/-/linkedom-0.18.5.tgz", + "integrity": "sha512-JGLaGGtqtu+eOhYrC1wkWYTBcpVWL4AsnwAtMtgO1Q0gI0PuPJKI0zBBE+a/1BrhOE3Uw8JI/ycByAv5cLrAuQ==", "dev": true, "dependencies": { "css-select": "^5.1.0", @@ -11374,7 +11374,7 @@ "csstype": "^3.1.2" }, "devDependencies": { - "linkedom": "^0.16.4" + "linkedom": "^0.18.5" } }, "packages/lens": { diff --git a/package.json b/package.json index 5aea60249..371068f1b 100644 --- a/package.json +++ b/package.json @@ -47,7 +47,7 @@ "core-js": "^3.37.1", "history": "^5.3.0", "husky": "^8.0.3 ", - "linkedom": "^0.16.10", + "linkedom": "^0.18.5", "lit": "^3.1.2", "microbundle": "^0.15.1", "react": "^18.2.0", diff --git a/packages/jsx/package.json b/packages/jsx/package.json index 5ab751b0e..2015cf2c4 100644 --- a/packages/jsx/package.json +++ b/packages/jsx/package.json @@ -41,7 +41,7 @@ "csstype": "^3.1.2" }, "devDependencies": { - "linkedom": "^0.16.4" + "linkedom": "^0.18.5" }, "author": "artalar", "maintainers": [ diff --git a/packages/jsx/src/index.test.tsx b/packages/jsx/src/index.test.tsx index a074f0cce..1c3dc31a9 100644 --- a/packages/jsx/src/index.test.tsx +++ b/packages/jsx/src/index.test.tsx @@ -516,10 +516,11 @@ test('ref mount and unmount callbacks order', async () => { ) mount(parent, component) + await sleep() parent.remove() await sleep() - assert.equal(order, [2, 1, 0, 2, 1, 0]) + assert.equal(order, [2, 1, 0, 0, 1, 2]) }) test('style object update', () => { diff --git a/packages/jsx/src/index.ts b/packages/jsx/src/index.ts index ac8518166..4206cf10a 100644 --- a/packages/jsx/src/index.ts +++ b/packages/jsx/src/index.ts @@ -263,14 +263,20 @@ export const reatomJsx = (ctx: Ctx, DOM: DomApis = globalThis.window) => { new DOM.MutationObserver((mutationsList) => { for (let mutation of mutationsList) { for (let removedNode of mutation.removedNodes) { - let list = unsubscribesMap.get(removedNode as any) - if (list) { - list.forEach((fn) => fn()) - unsubscribesMap.delete(removedNode as any) - } + /** + * @see https://stackoverflow.com/a/64551276 + * @note A custom NodeFilter function slows down performance by 1.5 times. + */ + const walker = DOM.document.createTreeWalker(removedNode, 1) + + do { + const node = walker.currentNode as Element + unsubscribesMap.get(node)?.forEach((fn) => fn()) + unsubscribesMap.delete(node) + } while (walker.nextNode()) } } - }).observe(target, { + }).observe(target.parentElement!, { childList: true, subtree: true, })