fix(runtime-core): properly handle async component update before resolve#11619
fix(runtime-core): properly handle async component update before resolve#11619edison1105 merged 8 commits intovuejs:mainfrom
Conversation
Size ReportBundles
Usages
|
| // the instance may be destroyed during the time period | ||
| if (!instance.isUnmounted) { | ||
| componentUpdateFn() | ||
| instance.update() |
There was a problem hiding this comment.
| instance.update() | |
| update() |
|
Thank you for addressing the issue. |
| // the instance may be destroyed during the time period | ||
| if (!instance.isUnmounted) { | ||
| componentUpdateFn() | ||
| update() |
There was a problem hiding this comment.
There is another problem here. The update() is executed 2 times.
This behavior is not related to this PR. But it needs to be fixed.
The flow is as follows:
- When
locateNonHydratedAsyncRootis called,subComponent.asyncResolvedisfalse,nonHydratedAsyncRoothas a value, and athencallback is registered. - The
thencallback is triggered and callsupdate. - We go back to step 1, but
subComponent.asyncResolvedis stillfalsebecause thethenat this line is registered later and executes after the previously registeredthen. Thethencallback is registered again. - Same as step 2.
- Now
subComponent.asyncResolvedistrue, andnonHydratedAsyncRootisundefined. - The remaining update logic runs.
In this process, the then callback gets registered twice, and update is called twice.
The following code can be used to prevent this behavior.
nonHydratedAsyncRoot.asyncDep!.then(() => {
// the instance may be destroyed during the time period
queuePostRenderEffect(()=>{
if (!instance.isUnmounted) update()
},parentSuspense)
})|
I'm pretty sure the previous fix is proper. |
|
@edison1105 I tried to fix it again, maybe it should be handled like this
You are right! I was wrong. I thought that when patching suspense, I had to confirm which component was pending, but this has nothing to do with pendingBranch. |
@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: |
📝 WalkthroughWalkthroughA new test verifies prop updates to async components inside Suspense; renderer update logic was changed to defer post-resolution updates by scheduling them with queuePostRenderEffect instead of calling updates synchronously. Changes
Sequence Diagram(s)sequenceDiagram
participant Parent as ParentComponent
participant Suspense as SuspenseBoundary
participant Async as AsyncChildComponent
participant Renderer
Parent->>Suspense: Render async child (dynamic)
Suspense->>Async: Mount -> async setup (suspends)
Parent->>Async: Prop update (before resolve)
Async->>Renderer: Request update (while suspended)
Renderer->>Renderer: queuePostRenderEffect(update) (defer)
note right of Renderer: waits for async resolve
Async-->>Suspense: Resolves
Renderer->>Async: Run deferred update if still mounted
Async-->>Parent: onUpdated / re-render completes
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes Possibly related PRs
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)
Comment |
|
/ecosystem-ci run |
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Fix all issues with AI agents
In `@packages/runtime-core/__tests__/components/Suspense.spec.ts`:
- Around line 2185-2241: Await the render and make the test deterministic by
using fake timers and advancing them so the async onMounted in Parent runs
before the test exits: call the test runtime's fake-timer setup (e.g.,
jest.useFakeTimers()/vi.useFakeTimers()), await render(h(App), root), advance
timers by 1000ms (e.g., jest.advanceTimersByTime(1000) or runAllTimers), then
await nextTick()/microtask flush before checking the expectation inside Parent's
onMounted (the expect(arr) assertion) or resolve a done promise after the
assertion so the test waits for completion; update the test around Parent, App,
and the render call to implement these changes.
|
📝 Ran ecosystem CI: Open
|
close #11617
this pr playground
Summary by CodeRabbit
Bug Fixes
Tests