1065
setErrorHandler,
1066
setSuspenseHandler,
1067
scheduleUpdate,
1068
+ scheduleRetry,
1069
getCurrentFiber,
1070
} = renderer;
1071
const supportsTogglingError =
7755
// First override is added. Switch React to slower path.
7756
setErrorHandler(shouldErrorFiberAccordingToMap);
7757
}
7757
- scheduleUpdate(fiber);
7758
+ if (!forceError && typeof scheduleRetry === 'function') {
7759
+ // If we're dismissing an error and the renderer supports it, use a Retry instead of Sync
7760
+ // This would allow View Transitions to proceed as if the error was dismissed using a Transition.
7761
+ scheduleRetry(fiber);
7762
+ } else {
7763
+ scheduleUpdate(fiber);
7764
+ }
7765
}
7766
7767
function shouldSuspendFiberAlwaysFalse() {
7819
setSuspenseHandler(shouldSuspendFiberAlwaysFalse);
7820
}
7821
}
7815
- scheduleUpdate(fiber);
7822
+ if (!forceFallback && typeof scheduleRetry === 'function') {
7823
+ // If we're unsuspending and the renderer supports it, use a Retry instead of Sync
7824
+ // to allow for things like View Transitions to proceed the way they would for real.
7825
+ scheduleRetry(fiber);
7826
+ } else {
7827
+ scheduleUpdate(fiber);
7828
+ }
7829
}
7830
7831
/**
7847
}
7848
7849
// TODO: Allow overriding the timeline for the specified root.
7837
- forceFallbackForFibers.forEach(fiber => {
7838
- scheduleUpdate(fiber);
7839
- });
7840
- forceFallbackForFibers.clear();
7850
7851
+ const unsuspendedSet: Set<Fiber> = new Set(forceFallbackForFibers);
7852
+
7853
+ let resuspended = false;
7854
for (let i = 0; i < suspendedSet.length; ++i) {
7855
const instance = idToDevToolsInstanceMap.get(suspendedSet[i]);
7856
if (instance === undefined) {
7862
7863
if (instance.kind === FIBER_INSTANCE) {
7864
const fiber = instance.data;
7853
- forceFallbackForFibers.add(fiber);
7854
- // We could find a minimal set that covers all the Fibers in this suspended set.
7855
- // For now we rely on React's batching of updates.
7856
- scheduleUpdate(fiber);
7865
+ if (
7866
+ forceFallbackForFibers.has(fiber) ||
7867
+ (fiber.alternate !== null &&
7868
+ forceFallbackForFibers.has(fiber.alternate))
7869
+ ) {
7870
+ // We're already forcing fallback for this fiber. Mark it as not unsuspended.
7871
+ unsuspendedSet.delete(fiber);
7872
+ if (fiber.alternate !== null) {
7873
+ unsuspendedSet.delete(fiber.alternate);
7874
+ }
7875
+ } else {
7876
+ forceFallbackForFibers.add(fiber);
7877
+ // We could find a minimal set that covers all the Fibers in this suspended set.
7878
+ // For now we rely on React's batching of updates.
7879
+ scheduleUpdate(fiber);
7880
+ resuspended = true;
7881
+ }
7882
} else {
7883
console.warn(`Cannot not suspend ID '${suspendedSet[i]}'.`);
7884
}
7885
}
7886
7887
+ // Unsuspend any existing forced fallbacks if they're not in the new set.
7888
+ unsuspendedSet.forEach(fiber => {
7889
+ forceFallbackForFibers.delete(fiber);
7890
+ if (!resuspended && typeof scheduleRetry === 'function') {
7891
+ // If nothing new resuspended we don't need this to be sync. If we're only
7892
+ // unsuspending then we can schedule this as a Retry if the renderer supports it.
7893
+ // That way we can trigger animations.
7894
+ scheduleRetry(fiber);
7895
+ } else {
7896
+ scheduleUpdate(fiber);
7897
+ }
7898
+ });
7899
+
7900
if (forceFallbackForFibers.size > 0) {
7901
// First override is added. Switch React to slower path.
7902
// TODO: Semantics for suspending a timeline are different. We want a suspended