398
} from './ReactFiberRootScheduler';
399
import {getMaskedContext, getUnmaskedContext} from './ReactFiberLegacyContext';
400
import {logUncaughtError} from './ReactFiberErrorLogger';
401
-import {
402
- deleteScheduledGesture,
403
- stopCompletedGestures,
404
-} from './ReactFiberGestureScheduler';
401
+import {stopCommittedGesture} from './ReactFiberGestureScheduler';
402
import {claimQueuedTransitionTypes} from './ReactFiberTransitionTypes';
403
404
const PossiblyWeakMap = typeof WeakMap === 'function' ? WeakMap : Map;
1404
1405
if (shouldForceFlushFallbacksInDEV()) {
1406
// We're inside an `act` scope. Commit immediately.
1410
- commitRoot(
1407
+ completeRoot(
1408
root,
1409
finishedWork,
1410
lanes,
1414
workInProgressDeferredLane,
1415
workInProgressRootInterleavedUpdatedLanes,
1416
workInProgressSuspendedRetryLanes,
1417
+ workInProgressRootDidSkipSuspendedSiblings,
1418
exitStatus,
1419
null,
1420
null,
1456
// run one after the other.
1457
pendingEffectsLanes = lanes;
1458
root.timeoutHandle = scheduleTimeout(
1461
- commitRootWhenReady.bind(
1459
+ completeRootWhenReady.bind(
1460
null,
1461
root,
1462
finishedWork,
1478
return;
1479
}
1480
}
1483
- commitRootWhenReady(
1481
+ completeRootWhenReady(
1482
root,
1483
finishedWork,
1484
workInProgressRootRecoverableErrors,
1497
}
1498
}
1499
1502
-function commitRootWhenReady(
1500
+function completeRootWhenReady(
1501
root: FiberRoot,
1502
finishedWork: Fiber,
1503
recoverableErrors: Array<CapturedValue<mixed>> | null,
1538
// This will also track any newly added or appearing ViewTransition
1539
// components for the purposes of forming pairs.
1540
accumulateSuspenseyCommit(finishedWork, lanes, suspendedState);
1543
- if (isViewTransitionEligible || isGestureTransition) {
1544
- // If we're stopping gestures we don't have to wait for any pending
1545
- // view transition. We'll stop it when we commit.
1546
- if (!enableGestureTransition || root.stoppingGestures === null) {
1547
- suspendOnActiveViewTransition(suspendedState, root.containerInfo);
1548
- }
1541
+ if (
1542
+ isViewTransitionEligible ||
1543
+ (isGestureTransition &&
1544
+ root.pendingGestures !== null &&
1545
+ // If we're committing this gesture and it already has a View Transition
1546
+ // running, then we don't have to wait for that gesture. We'll stop it
1547
+ // when we commit.
1548
+ (root.pendingGestures.running === null ||
1549
+ !root.pendingGestures.committing))
1550
+ ) {
1551
+ // Wait for any pending View Transition (including gestures) to finish.
1552
+ suspendOnActiveViewTransition(suspendedState, root.containerInfo);
1553
}
1554
// For timeouts we use the previous fallback commit for retries and
1555
// the start time of the transition for transitions. This offset
1576
// root again.
1577
pendingEffectsLanes = lanes;
1578
root.cancelPendingCommit = schedulePendingCommit(
1575
- commitRoot.bind(
1579
+ completeRoot.bind(
1580
null,
1581
root,
1582
finishedWork,
1587
spawnedLane,
1588
updatedLanes,
1589
suspendedRetryLanes,
1590
+ didSkipSuspendedSiblings,
1591
exitStatus,
1592
suspendedState,
1593
enableProfilerTimer
1604
}
1605
1606
// Otherwise, commit immediately.;
1602
- commitRoot(
1607
+ completeRoot(
1608
root,
1609
finishedWork,
1610
lanes,
1614
spawnedLane,
1615
updatedLanes,
1616
suspendedRetryLanes,
1617
+ didSkipSuspendedSiblings,
1618
exitStatus,
1619
suspendedState,
1620
suspendedCommitReason,
3426
workInProgress = null;
3427
}
3428
3423
-function commitRoot(
3429
+function completeRoot(
3430
root: FiberRoot,
3431
finishedWork: null | Fiber,
3432
lanes: Lanes,
3436
spawnedLane: Lane,
3437
updatedLanes: Lanes,
3438
suspendedRetryLanes: Lanes,
3439
+ didSkipSuspendedSiblings: boolean,
3440
exitStatus: RootExitStatus,
3441
suspendedState: null | SuspendedState,
3442
suspendedCommitReason: SuspendedCommitReason, // Profiling-only
3503
markCommitStopped();
3504
}
3505
if (enableGestureTransition) {
3499
- // Stop any gestures that were completed and is now being reverted.
3500
- if (root.stoppingGestures !== null) {
3501
- stopCompletedGestures(root);
3506
+ // Stop any gestures that were committed.
3507
+ if (isGestureRender(lanes)) {
3508
+ stopCommittedGesture(root);
3509
}
3510
}
3511
return;
3527
);
3528
}
3529
3530
+ if (root === workInProgressRoot) {
3531
+ // We can reset these now that they are finished.
3532
+ workInProgressRoot = null;
3533
+ workInProgress = null;
3534
+ workInProgressRootRenderLanes = NoLanes;
3535
+ } else {
3536
+ // This indicates that the last root we worked on is not the same one that
3537
+ // we're committing now. This most commonly happens when a suspended root
3538
+ // times out.
3539
+ }
3540
+
3541
+ // workInProgressX might be overwritten, so we want
3542
+ // to store it in pendingPassiveX until they get processed
3543
+ // We need to pass this through as an argument to completeRoot
3544
+ // because workInProgressX might have changed between
3545
+ // the previous render and commit if we throttle the commit
3546
+ // with setTimeout
3547
+ pendingFinishedWork = finishedWork;
3548
+ pendingEffectsRoot = root;
3549
+ pendingEffectsLanes = lanes;
3550
+ pendingPassiveTransitions = transitions;
3551
+ pendingRecoverableErrors = recoverableErrors;
3552
+ pendingDidIncludeRenderPhaseUpdate = didIncludeRenderPhaseUpdate;
3553
+ if (enableProfilerTimer) {
3554
+ pendingEffectsRenderEndTime = completedRenderEndTime;
3555
+ pendingSuspendedCommitReason = suspendedCommitReason;
3556
+ pendingDelayedCommitReason = IMMEDIATE_COMMIT;
3557
+ pendingSuspendedViewTransitionReason = null;
3558
+ }
3559
+
3560
+ if (enableGestureTransition && isGestureRender(lanes)) {
3561
+ const committingGesture = root.pendingGestures;
3562
+ if (committingGesture !== null && !committingGesture.committing) {
3563
+ // This gesture is not ready to commit yet. We'll mark it as suspended and
3564
+ // start a gesture transition which isn't really a side-effect. Then later
3565
+ // we might come back around to actually committing the root.
3566
+ const didAttemptEntireTree = !didSkipSuspendedSiblings;
3567
+ markRootSuspended(root, lanes, spawnedLane, didAttemptEntireTree);
3568
+ if (committingGesture.running === null) {
3569
+ applyGestureOnRoot(
3570
+ root,
3571
+ finishedWork,
3572
+ recoverableErrors,
3573
+ suspendedState,
3574
+ enableProfilerTimer
3575
+ ? suspendedCommitReason === null
3576
+ ? completedRenderEndTime
3577
+ : commitStartTime
3578
+ : 0,
3579
+ );
3580
+ } else {
3581
+ // If we already have a gesture running, we don't update it in place
3582
+ // even if we have a new tree. Instead we wait until we can commit.
3583
+ }
3584
+ return;
3585
+ }
3586
+ }
3587
+
3588
+ // If we're not starting a gesture we now actually commit the root.
3589
+ commitRoot(
3590
+ root,
3591
+ finishedWork,
3592
+ lanes,
3593
+ spawnedLane,
3594
+ updatedLanes,
3595
+ suspendedRetryLanes,
3596
+ suspendedState,
3597
+ suspendedCommitReason,
3598
+ completedRenderEndTime,
3599
+ );
3600
+}
3601
+
3602
+function commitRoot(
3603
+ root: FiberRoot,
3604
+ finishedWork: Fiber,
3605
+ lanes: Lanes,
3606
+ spawnedLane: Lane,
3607
+ updatedLanes: Lanes,
3608
+ suspendedRetryLanes: Lanes,
3609
+ suspendedState: null | SuspendedState,
3610
+ suspendedCommitReason: SuspendedCommitReason, // Profiling-only
3611
+ completedRenderEndTime: number, // Profiling-only
3612
+) {
3613
// Check which lanes no longer have any work scheduled on them, and mark
3614
// those as finished.
3615
let remainingLanes = mergeLanes(finishedWork.lanes, finishedWork.childLanes);
3616
3617
+ pendingEffectsRemainingLanes = remainingLanes;
3618
+
3619
// Make sure to account for lanes that were updated by a concurrent event
3620
// during the render phase; don't mark them as finished.
3621
const concurrentlyUpdatedLanes = getConcurrentlyUpdatedLanes();
3645
// Reset this before firing side effects so we can detect recursive updates.
3646
didIncludeCommitPhaseUpdate = false;
3647
3556
- if (root === workInProgressRoot) {
3557
- // We can reset these now that they are finished.
3558
- workInProgressRoot = null;
3559
- workInProgress = null;
3560
- workInProgressRootRenderLanes = NoLanes;
3561
- } else {
3562
- // This indicates that the last root we worked on is not the same one that
3563
- // we're committing now. This most commonly happens when a suspended root
3564
- // times out.
3565
- }
3566
-
3567
- // workInProgressX might be overwritten, so we want
3568
- // to store it in pendingPassiveX until they get processed
3569
- // We need to pass this through as an argument to commitRoot
3570
- // because workInProgressX might have changed between
3571
- // the previous render and commit if we throttle the commit
3572
- // with setTimeout
3573
- pendingFinishedWork = finishedWork;
3574
- pendingEffectsRoot = root;
3575
- pendingEffectsLanes = lanes;
3576
- pendingEffectsRemainingLanes = remainingLanes;
3577
- pendingPassiveTransitions = transitions;
3578
- pendingRecoverableErrors = recoverableErrors;
3579
- pendingDidIncludeRenderPhaseUpdate = didIncludeRenderPhaseUpdate;
3580
- if (enableProfilerTimer) {
3581
- pendingEffectsRenderEndTime = completedRenderEndTime;
3582
- pendingSuspendedCommitReason = suspendedCommitReason;
3583
- pendingDelayedCommitReason = IMMEDIATE_COMMIT;
3584
- pendingSuspendedViewTransitionReason = null;
3585
- }
3586
-
3587
- if (enableGestureTransition && isGestureRender(lanes)) {
3588
- // This is a special kind of render that doesn't commit regular effects.
3589
- commitGestureOnRoot(
3590
- root,
3591
- finishedWork,
3592
- recoverableErrors,
3593
- suspendedState,
3594
- enableProfilerTimer
3595
- ? suspendedCommitReason === null
3596
- ? completedRenderEndTime
3597
- : commitStartTime
3598
- : 0,
3599
- );
3600
- return;
3601
- }
3602
-
3648
// If there are pending passive effects, schedule a callback to process them.
3649
// Do this as early as possible, so it is queued before anything else that
3650
// might get scheduled in the commit phase. (See #16714.)
3757
}
3758
}
3759
3715
- let willStartViewTransition = shouldStartViewTransition;
3760
if (enableGestureTransition) {
3717
- // Stop any gestures that were completed and is now being committed.
3718
- if (root.stoppingGestures !== null) {
3719
- stopCompletedGestures(root);
3720
- // If we are in the process of stopping some gesture we shouldn't start
3721
- // a View Transition because that would start from the previous state to
3722
- // the next state.
3723
- willStartViewTransition = false;
3761
+ // Stop any gestures that were committed.
3762
+ if (isGestureRender(lanes)) {
3763
+ stopCommittedGesture(root);
3764
+ // Note that shouldStartViewTransition should always be false here because
3765
+ // committing a gesture never starts a new View Transition itself since it's
3766
+ // not a View Transition eligible lane. Only follow up Transition commits can
3767
+ // cause animate.
3768
}
3769
}
3770
3771
pendingEffectsStatus = PENDING_MUTATION_PHASE;
3728
- if (enableViewTransition && willStartViewTransition) {
3772
+ if (enableViewTransition && shouldStartViewTransition) {
3773
if (enableProfilerTimer && enableComponentPerformanceTrack) {
3774
startAnimating(lanes);
3775
}
4199
flushPendingEffects();
4200
}
4201
4158
- // Always call this before exiting `commitRoot`, to ensure that any
4202
+ // Always call this before exiting `completeRoot`, to ensure that any
4203
// additional work on this root is scheduled.
4204
ensureRootIsScheduled(root);
4205
4288
}
4289
}
4290
4247
-function commitGestureOnRoot(
4291
+function applyGestureOnRoot(
4292
root: FiberRoot,
4293
finishedWork: Fiber,
4294
recoverableErrors: null | Array<CapturedValue<mixed>>,
4303
ensureRootIsScheduled(root);
4304
return;
4305
}
4262
- deleteScheduledGesture(root, finishedGesture);
4306
4307
if (enableProfilerTimer && enableComponentPerformanceTrack) {
4308
startAnimating(pendingEffectsLanes);
4511
// flushPassiveEffectsImpl
4512
const root = pendingEffectsRoot;
4513
// Cache and clear the remaining lanes flag; it must be reset since this
4471
- // method can be called from various places, not always from commitRoot
4514
+ // method can be called from various places, not always from completeRoot
4515
// where the remaining lanes are known
4516
const remainingLanes = pendingEffectsRemainingLanes;
4517
pendingEffectsRemainingLanes = NoLanes;
4899
ensureRootIsScheduled(root);
4900
}
4901
4902
+export function pingGestureRoot(root: FiberRoot): void {
4903
+ const gesture = root.pendingGestures;
4904
+ if (gesture === null) {
4905
+ return;
4906
+ }
4907
+ if (
4908
+ root.cancelPendingCommit !== null &&
4909
+ isGestureRender(pendingEffectsLanes)
4910
+ ) {
4911
+ // We have a suspended commit which we'll discard and rerender.
4912
+ // TODO: Just use this commit since it's ready to go.
4913
+ const cancelPendingCommit = root.cancelPendingCommit;
4914
+ if (cancelPendingCommit !== null) {
4915
+ root.cancelPendingCommit = null;
4916
+ cancelPendingCommit();
4917
+ }
4918
+ }
4919
+ // Ping it for rerender and commit.
4920
+ markRootPinged(root, GestureLane);
4921
+ ensureRootIsScheduled(root);
4922
+}
4923
+
4924
+export function restartGestureRoot(root: FiberRoot): void {
4925
+ if (
4926
+ workInProgressRoot === root &&
4927
+ isGestureRender(workInProgressRootRenderLanes)
4928
+ ) {
4929
+ // The current render was a gesture but it's now defunct. We need to restart the render.
4930
+ if ((executionContext & RenderContext) === NoContext) {
4931
+ prepareFreshStack(root, NoLanes);
4932
+ } else {
4933
+ // TODO: Throw interruption when supported again.
4934
+ }
4935
+ } else if (
4936
+ root.cancelPendingCommit !== null &&
4937
+ isGestureRender(pendingEffectsLanes)
4938
+ ) {
4939
+ // We have a suspended commit which we'll discard.
4940
+ const cancelPendingCommit = root.cancelPendingCommit;
4941
+ if (cancelPendingCommit !== null) {
4942
+ root.cancelPendingCommit = null;
4943
+ cancelPendingCommit();
4944
+ }
4945
+ }
4946
+ if (root.pendingGestures !== null) {
4947
+ // We still have gestures to work on. Let's schedule a restart.
4948
+ markRootPinged(root, GestureLane);
4949
+ }
4950
+ ensureRootIsScheduled(root);
4951
+}
4952
+
4953
function retryTimedOutBoundary(boundaryFiber: Fiber, retryLane: Lane) {
4954
// The boundary fiber (a Suspense component or SuspenseList component)
4955
// previously was rendered in its fallback state. One of the promises that