fix(suspense): avoid unmount activeBranch twice if wrapped in transition#9392
Conversation
Size ReportBundles
Usages
|
|
@edison1105 I don't think the solution is good enough, from what I could gather this is caused by the renderer.ts Basically the I suppose it would make sense the |
|
@pikax |
chore: improve code chore: improve code chore: improve code chore(deps): update dependency @types/node to v18 (vuejs#9323) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> chore: improve code chore: revert code chore: improve code
📝 WalkthroughWalkthroughAdds a boolean flag Changes
Sequence Diagram(s)sequenceDiagram
participant App as Client
participant T as Transition (out-in)
participant S as Suspense
participant R as Renderer/DOM
App->>T: swap shallowRef (One -> Two)
T->>S: trigger leave (out-in)
S->>S: fallback() sets isFallbackMountPending = true\nattach afterLeave -> mountFallback
T->>T: afterLeave fires
T->>S: mountFallback (clear isFallbackMountPending = false)
S->>R: mount fallback subtree
S->>S: resolve() clears flag and swaps activeBranch (no double-unmount)
S->>R: unmount old branch (once) and mount resolved branch
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Comment |
@vue/compiler-core
@vue/compiler-dom
@vue/compiler-sfc
@vue/compiler-ssr
@vue/reactivity
@vue/runtime-core
@vue/runtime-dom
@vue/server-renderer
@vue/shared
vue
@vue/compat
commit: |
There was a problem hiding this comment.
Actionable comments posted: 2
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@packages/runtime-core/src/components/Suspense.ts`:
- Around line 566-570: The current logic skips unmounting
suspense.initialContent in resolve() but fallback() still flips isInFallback
before the fallback vnode is actually mounted, allowing patchSuspense() (which
checks pendingBranch && isInFallback) to treat the leaving initialContent as if
the fallback were active and unmount the same vnode twice; to fix, make the
isInFallback checks in patchSuspense() and any branches that act on
pendingBranch also verify that activeBranch !== suspense.initialContent (or that
suspense.initialContent is not the leaving node) before patching/unmounting, or
alternatively ensure unmount operations on the same vnode are idempotent at the
renderer level (adjust unmount logic used by patchSuspense(), resolve(), and
fallback() to guard against re-unmounting the same vnode).
- Line 651: The Suspense instance's initialContent remains set when the
fast-resolve path wins because resolve() replaces the afterLeave callback but
doesn't clear suspense.initialContent; update the resolve() logic in the
Suspense implementation (the resolve() method that interacts with
mountFallback() and afterLeave) to explicitly set suspense.initialContent = null
when the pending branch is replaced so the old vnode/component tree is released
once the new branch takes over.
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: 3f881373-2fcb-46cf-b0a8-d94e8eae6d1e
📒 Files selected for processing (2)
packages/runtime-core/src/components/Suspense.tspackages/vue/__tests__/e2e/Transition.spec.ts
|
/ecosystem-ci run |
|
📝 Ran ecosystem CI: Open
|
close #7966
the root cause is that the suspense resolves before the fallback node is mounted. This caused component B to be unmounted twice, causing this issue when it was unmounted the second time. see simplified demo
Notice the Console,
unmountwas printed twice.Summary by CodeRabbit
Bug Fixes
Tests