Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 10 additions & 1 deletion compat/src/suspense.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ const oldUnmount = options.unmount;
options.unmount = function (vnode) {
/** @type {import('./internal').Component} */
const component = vnode._component;
if (component) component._unmounted = true;
if (component && component._onResolve) {
component._onResolve();
}
Expand Down Expand Up @@ -127,7 +128,7 @@ Suspense.prototype._childDidSuspend = function (promise, suspendingVNode) {

let resolved = false;
const onResolved = () => {
if (resolved) return;
if (resolved || c._unmounted) return;

resolved = true;
suspendingComponent._onResolve = null;
Expand All @@ -137,6 +138,12 @@ Suspense.prototype._childDidSuspend = function (promise, suspendingVNode) {

suspendingComponent._onResolve = onResolved;

// Store and null _parentDom to prevent setState/forceUpdate from
// scheduling renders while suspended. Render would be a no-op anyway
// since renderComponent checks _parentDom, but this avoids queue churn.
const originalParentDom = suspendingComponent._parentDom;
suspendingComponent._parentDom = null;

const onSuspensionComplete = () => {
if (!--c._pendingSuspensionCount) {
// If the suspension was during hydration we don't need to restore the
Expand All @@ -154,6 +161,8 @@ Suspense.prototype._childDidSuspend = function (promise, suspendingVNode) {

let suspended;
while ((suspended = c._suspenders.pop())) {
// Restore _parentDom before forceUpdate so render can proceed
suspended._parentDom = originalParentDom;
suspended.forceUpdate();
}
}
Expand Down
Loading
Loading