fix(runtime-core): skip idle persisted transition hooks in keep-alive moves#14865
Conversation
📝 WalkthroughWalkthroughRenderer move() now skips enter/leave hooks for persisted transitions; a unit test verifies persisted transitions inside KeepAlive do not fire enter/leave during cached component activation/deactivation, and an e2e test's transition timing was parameterized to match a longer duration. ChangesPersisted Transition Behavior Fix
E2E Transition test timing update
Estimated code review effort🎯 4 (Complex) | ⏱️ ~40 minutes Possibly related PRs
Suggested labels
Suggested reviewers
Poem
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. 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: |
| shapeFlag & ShapeFlags.ELEMENT && | ||
| transition | ||
| transition && | ||
| !transition.persisted |
Address @edison1105's review: the previous blanket `!transition.persisted` guard on `needTransition` regressed vuejs#13153 because it routed persisted leaves through the bare `hostInsert` fallback, skipping the `_isLeaving` / `leaveCbKey` cancellation that vuejs#13153 added. Restructure the move() branch so persisted transitions still take the needTransition path (preserving the _isLeaving cancellation in performLeave) but skip only the directive-owned beforeEnter/enter and leave/afterLeave calls. Existing vuejs#14031 test still passes; full runtime-core + runtime-dom suites green (1245/1246, one pre-existing skip).
|
Thanks for catching that, @edison1105 — you're right, the Pushed ff7a800: kept persisted transitions on the The #14031 test still passes, and full |
2e53ace to
9ee1b75
Compare
|
Thanks, I pushed a follow-up that keeps the see 9ee1b75 |
Size ReportBundles
Usages
|
|
/ecosystem-ci run |
|
📝 Ran ecosystem CI: Open
|
Fixes #14031.
When a
<keep-alive>activates or deactivates a cached child, the renderer'smovefunction callstransition.beforeEnter/transition.enter(orleave) on every element vnode that carries a transition. For a normal transition this is correct, but for a persisted transition (the flag the template compiler injects when<Transition>has a singlev-showchild) the lifecycle is owned by the directive, not by mount/move. The element is being moved in or out of a detached storage container; the visibility is already controlled byv-show.As a result, every cache hit was firing
onBeforeEnter/onEnterand (because no async hook keeps it pending)onAfterEnter, even when thev-showtarget was never displayed. The reproduction in the issue uses av-show="false"element inside a<keep-alive>and observesafter-enterlogged on each toggle.The fix extends the same
!transition.persistedguard thatmountElementalready uses (via the module-levelneedTransitionhelper) to the per-element branch insidemove. Persisted transitions still get theirhostInsertso the element is correctly relocated between the live tree and the keep-alive storage container, but the directive-owned enter / leave hooks are no longer called behind the directive's back. The existing#13153interaction with_isLeavinglives outside the persisted path and is unaffected.Added a regression test in
BaseTransition.spec.tsthat wraps aKeepAliveswitching between two components inside aBaseTransitionwithpersisted: trueand asserts that none of the enter or leave hooks fire on activate or deactivate. The test fails onmain(the deactivate path callsonBeforeLeave/onLeaveand the activate path calls all three enter hooks via the immediatedone()inBaseTransition) and passes with the change.Summary by CodeRabbit
Bug Fixes
Tests