]> git.ipfire.org Git - thirdparty/vuejs/core.git/commitdiff
fix: avoid duplicate rendering of children
authordaiwei <daiwei521@126.com>
Fri, 8 Aug 2025 03:10:31 +0000 (11:10 +0800)
committerdaiwei <daiwei521@126.com>
Fri, 8 Aug 2025 03:10:31 +0000 (11:10 +0800)
Revert "fix(hydration): handle v-if on insertion parent"
This reverts commit 9d3ee8e2ec66bdcee341b8c6c105d5ab37985e44.

packages/runtime-vapor/src/apiCreateIf.ts
packages/runtime-vapor/src/dom/template.ts
packages/runtime-vapor/src/fragment.ts
packages/runtime-vapor/src/insertionState.ts

index cec91af0a9ecf39957810ff5ccc0839e44661054..01a9e3eb3aa24209272993ebf6348e683b059fd1 100644 (file)
@@ -9,37 +9,6 @@ import {
 import { renderEffect } from './renderEffect'
 import { DynamicFragment } from './fragment'
 
-const ifStack = [] as DynamicFragment[]
-const insertionParents = new WeakMap<DynamicFragment, Node[]>()
-
-/**
- * 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("<div></div>")
- * const n2 = _createIf(() => show.value, () => {
- *   const n5 = t2()
- *   _setInsertionState(n5)
- *   const n4 = _createComponent(Comp) // renders `<span></span>`
- *   return n5
- * })
- *
- * After hydration, the HTML of `n5` is `<div><span></span></div>` instead of `<div></div>`.
- * 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) {
index dbe2c35832e582b4368c10bc5e9375dd9309da86..e00e9d213f4d70d49082e4777407f4aa43b5082e 100644 (file)
@@ -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] !== '<') {
index 887d6d09bf6de3571f89ccdb8eea214c47b52c8e..9b37419e6e327d0429bff737516f3328ab13972b 100644 (file)
@@ -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)
index c89884cda8438093d49f6e1be6ff48328b9d6b99..292ffb43c42d8cbe43d103da24e9ce9f69e23af3 100644 (file)
@@ -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 {