125
computeAsyncExpiration,
126
computeInteractiveExpiration,
127
} from './ReactFiberExpirationTime';
128
-import {ConcurrentMode, ProfileMode, NoContext} from './ReactTypeOfMode';
129
-import {
130
- enqueueUpdate,
131
- resetCurrentlyProcessingQueue,
132
- ForceUpdate,
133
- createUpdate,
134
-} from './ReactUpdateQueue';
128
+import {ConcurrentMode, ProfileMode} from './ReactTypeOfMode';
129
+import {enqueueUpdate, resetCurrentlyProcessingQueue} from './ReactUpdateQueue';
130
import {createCapturedValue} from './ReactCapturedValue';
131
import {
132
isContextProvider as isLegacyContextProvider,
1641
nextRenderDidError = true;
1642
}
1643
1649
-function retrySuspendedRoot(
1644
+function pingSuspendedRoot(
1645
root: FiberRoot,
1651
- boundaryFiber: Fiber,
1652
- sourceFiber: Fiber,
1653
- suspendedTime: ExpirationTime,
1646
+ thenable: Thenable,
1647
+ pingTime: ExpirationTime,
1648
) {
1655
- let retryTime;
1649
+ // A promise that previously suspended React from committing has resolved.
1650
+ // If React is still suspended, try again at the previous level (pingTime).
1651
1657
- if (isPriorityLevelSuspended(root, suspendedTime)) {
1658
- // Ping at the original level
1659
- retryTime = suspendedTime;
1652
+ const pingCache = root.pingCache;
1653
+ if (pingCache !== null) {
1654
+ // The thenable resolved, so we no longer need to memoize, because it will
1655
+ // never be thrown again.
1656
+ pingCache.delete(thenable);
1657
+ }
1658
1661
- markPingedPriorityLevel(root, retryTime);
1659
+ if (nextRoot !== null && nextRenderExpirationTime === pingTime) {
1660
+ // Received a ping at the same priority level at which we're currently
1661
+ // rendering. Restart from the root.
1662
+ nextRoot = null;
1663
} else {
1663
- // Suspense already timed out. Compute a new expiration time
1664
- const currentTime = requestCurrentTime();
1665
- retryTime = computeExpirationForFiber(currentTime, boundaryFiber);
1666
- markPendingPriorityLevel(root, retryTime);
1664
+ // Confirm that the root is still suspended at this level. Otherwise exit.
1665
+ if (isPriorityLevelSuspended(root, pingTime)) {
1666
+ // Ping at the original level
1667
+ markPingedPriorityLevel(root, pingTime);
1668
+ const rootExpirationTime = root.expirationTime;
1669
+ if (rootExpirationTime !== NoWork) {
1670
+ requestWork(root, rootExpirationTime);
1671
+ }
1672
+ }
1673
}
1674
+}
1675
1669
- // TODO: If the suspense fiber has already rendered the primary children
1670
- // without suspending (that is, all of the promises have already resolved),
1671
- // we should not trigger another update here. One case this happens is when
1672
- // we are in sync mode and a single promise is thrown both on initial render
1673
- // and on update; we attach two .then(retrySuspendedRoot) callbacks and each
1674
- // one performs Sync work, rerendering the Suspense.
1676
+function retryTimedOutBoundary(boundaryFiber: Fiber, thenable: Thenable) {
1677
+ // The boundary fiber (a Suspense component) previously timed out and was
1678
+ // rendered in its fallback state. One of the promises that suspended it has
1679
+ // resolved, which means at least part of the tree was likely unblocked. Try
1680
+ // rendering again, at a new expiration time.
1681
1676
- if ((boundaryFiber.mode & ConcurrentMode) !== NoContext) {
1677
- if (root === nextRoot && nextRenderExpirationTime === suspendedTime) {
1678
- // Received a ping at the same priority level at which we're currently
1679
- // rendering. Restart from the root.
1680
- nextRoot = null;
1681
- }
1682
+ const retryCache: WeakSet<Thenable> | Set<Thenable> | null =
1683
+ boundaryFiber.stateNode;
1684
+ if (retryCache !== null) {
1685
+ // The thenable resolved, so we no longer need to memoize, because it will
1686
+ // never be thrown again.
1687
+ retryCache.delete(thenable);
1688
}
1689
1684
- scheduleWorkToRoot(boundaryFiber, retryTime);
1685
- if ((boundaryFiber.mode & ConcurrentMode) === NoContext) {
1686
- // Outside of concurrent mode, we must schedule an update on the source
1687
- // fiber, too, since it already committed in an inconsistent state and
1688
- // therefore does not have any pending work.
1689
- scheduleWorkToRoot(sourceFiber, retryTime);
1690
- const sourceTag = sourceFiber.tag;
1691
- if (sourceTag === ClassComponent && sourceFiber.stateNode !== null) {
1692
- // When we try rendering again, we should not reuse the current fiber,
1693
- // since it's known to be in an inconsistent state. Use a force updte to
1694
- // prevent a bail out.
1695
- const update = createUpdate(retryTime);
1696
- update.tag = ForceUpdate;
1697
- enqueueUpdate(sourceFiber, update);
1690
+ const currentTime = requestCurrentTime();
1691
+ const retryTime = computeExpirationForFiber(currentTime, boundaryFiber);
1692
+ const root = scheduleWorkToRoot(boundaryFiber, retryTime);
1693
+ if (root !== null) {
1694
+ markPendingPriorityLevel(root, retryTime);
1695
+ const rootExpirationTime = root.expirationTime;
1696
+ if (rootExpirationTime !== NoWork) {
1697
+ requestWork(root, rootExpirationTime);
1698
}
1699
}
1700
-
1701
- const rootExpirationTime = root.expirationTime;
1702
- if (rootExpirationTime !== NoWork) {
1703
- requestWork(root, rootExpirationTime);
1704
- }
1700
}
1701
1702
function scheduleWorkToRoot(fiber: Fiber, expirationTime): FiberRoot | null {
2545
onUncaughtError,
2546
renderDidSuspend,
2547
renderDidError,
2553
- retrySuspendedRoot,
2548
+ pingSuspendedRoot,
2549
+ retryTimedOutBoundary,
2550
markLegacyErrorBoundaryAsFailed,
2551
isAlreadyFailedLegacyErrorBoundary,
2552
scheduleWork,