From: daiwei Date: Fri, 8 Aug 2025 03:10:31 +0000 (+0800) Subject: fix: avoid duplicate rendering of children X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=107350a3f568cc24e4cb29e8ec104ffb16f67154;p=thirdparty%2Fvuejs%2Fcore.git fix: avoid duplicate rendering of children Revert "fix(hydration): handle v-if on insertion parent" This reverts commit 9d3ee8e2ec66bdcee341b8c6c105d5ab37985e44. --- diff --git a/packages/runtime-vapor/src/apiCreateIf.ts b/packages/runtime-vapor/src/apiCreateIf.ts index cec91af0a9..01a9e3eb3a 100644 --- a/packages/runtime-vapor/src/apiCreateIf.ts +++ b/packages/runtime-vapor/src/apiCreateIf.ts @@ -9,37 +9,6 @@ import { import { renderEffect } from './renderEffect' import { DynamicFragment } from './fragment' -const ifStack = [] as DynamicFragment[] -const insertionParents = new WeakMap() - -/** - * Collects insertionParents inside an if block during hydration - * When the if condition becomes false on the client, clears the - * HTML of these insertionParents to prevent duplicate rendering - * results when the condition becomes true again - * - * Example: - * const t2 = _template("
") - * const n2 = _createIf(() => show.value, () => { - * const n5 = t2() - * _setInsertionState(n5) - * const n4 = _createComponent(Comp) // renders `` - * return n5 - * }) - * - * After hydration, the HTML of `n5` is `
` instead of `
`. - * When `show.value` becomes false, the HTML of `n5` needs to be cleared, - * to avoid duplicated rendering when `show.value` becomes true again. - */ -export function collectInsertionParents(insertionParent: ParentNode): void { - const currentIf = ifStack[ifStack.length - 1] - if (currentIf) { - let nodes = insertionParents.get(currentIf) - if (!nodes) insertionParents.set(currentIf, (nodes = [])) - nodes.push(insertionParent) - } -} - export function createIf( condition: () => any, b1: BlockFn, @@ -61,19 +30,7 @@ export function createIf( elseIf && isHydrating ? ELSE_IF_ANCHOR_LABEL : IF_ANCHOR_LABEL, ) : new DynamicFragment() - if (isHydrating) { - ;(frag as DynamicFragment).teardown = () => { - const nodes = insertionParents.get(frag as DynamicFragment) - if (nodes) { - nodes.forEach(p => ((p as Element).innerHTML = '')) - insertionParents.delete(frag as DynamicFragment) - } - ;(frag as DynamicFragment).teardown = undefined - } - ifStack.push(frag as DynamicFragment) - } renderEffect(() => (frag as DynamicFragment).update(condition() ? b1 : b2)) - isHydrating && ifStack.pop() } if (!isHydrating) { diff --git a/packages/runtime-vapor/src/dom/template.ts b/packages/runtime-vapor/src/dom/template.ts index dbe2c35832..e00e9d213f 100644 --- a/packages/runtime-vapor/src/dom/template.ts +++ b/packages/runtime-vapor/src/dom/template.ts @@ -12,9 +12,11 @@ export function template(html: string, root?: boolean) { // TODO this should not happen throw new Error('No current hydration node') } - node = adoptTemplate(currentHydrationNode!, html)! - if (root) (node as any).$root = true - return node + // do not cache the adopted node in node because it contains child nodes + // this avoids duplicate rendering of children + const adopted = adoptTemplate(currentHydrationNode!, html)! + if (root) (adopted as any).$root = true + return adopted } // fast path for text nodes if (html[0] !== '<') { diff --git a/packages/runtime-vapor/src/fragment.ts b/packages/runtime-vapor/src/fragment.ts index 887d6d09bf..9b37419e6e 100644 --- a/packages/runtime-vapor/src/fragment.ts +++ b/packages/runtime-vapor/src/fragment.ts @@ -61,7 +61,6 @@ export class DynamicFragment extends VaporFragment { * indicates forwarded slot */ forwarded?: boolean - teardown?: () => void anchorLabel?: string constructor(anchorLabel?: string) { @@ -102,7 +101,6 @@ export class DynamicFragment extends VaporFragment { // teardown previous branch if (this.scope) { this.scope.stop() - if (parent) this.teardown && this.teardown() const mode = transition && transition.mode if (mode) { applyTransitionLeaveHooks(this.nodes, transition, renderBranch) diff --git a/packages/runtime-vapor/src/insertionState.ts b/packages/runtime-vapor/src/insertionState.ts index c89884cda8..292ffb43c4 100644 --- a/packages/runtime-vapor/src/insertionState.ts +++ b/packages/runtime-vapor/src/insertionState.ts @@ -1,6 +1,3 @@ -import { collectInsertionParents } from './apiCreateIf' -import { isHydrating } from './dom/hydration' - export let insertionParent: | (ParentNode & { // number of prepends - hydration only @@ -26,10 +23,6 @@ export function setInsertionState( insertionParent = parent insertionAnchor = anchor insertionChildIndex = offset - - if (isHydrating) { - collectInsertionParents(parent) - } } export function resetInsertionState(): void {