163
164
import {
165
scheduleGesture,
166
+ scheduleGestureLegacy,
167
cancelScheduledGesture,
168
} from './ReactFiberGestureScheduler';
169
174
hasEagerState: boolean,
175
eagerState: S | null,
176
next: Update<S, A>,
177
+ gesture: null | ScheduledGesture, // enableSwipeTransition
178
};
179
180
export type UpdateQueue<S, A> = {
1379
// Check if this update was made while the tree was hidden. If so, then
1380
// it's not a "base" update and we should disregard the extra base lanes
1381
// that were added to renderLanes when we entered the Offscreen tree.
1380
- const shouldSkipUpdate = isHiddenUpdate
1382
+ let shouldSkipUpdate = isHiddenUpdate
1383
? !isSubsetOfLanes(getWorkInProgressRootRenderLanes(), updateLane)
1384
: !isSubsetOfLanes(renderLanes, updateLane);
1385
1386
+ if (enableSwipeTransition && updateLane === GestureLane) {
1387
+ // This is a gesture optimistic update. It should only be considered as part of the
1388
+ // rendered state while rendering the gesture lane and if the rendering the associated
1389
+ // ScheduledGesture.
1390
+ const scheduledGesture = update.gesture;
1391
+ if (scheduledGesture !== null) {
1392
+ if (scheduledGesture.count === 0) {
1393
+ // This gesture has already been cancelled. We can clean up this update.
1394
+ update = update.next;
1395
+ continue;
1396
+ } else if (!isGestureRender(renderLanes)) {
1397
+ shouldSkipUpdate = true;
1398
+ } else {
1399
+ const root: FiberRoot | null = getWorkInProgressRoot();
1400
+ if (root === null) {
1401
+ throw new Error(
1402
+ 'Expected a work-in-progress root. This is a bug in React. Please file an issue.',
1403
+ );
1404
+ }
1405
+ // We assume that the currently rendering gesture is the one first in the queue.
1406
+ shouldSkipUpdate = root.pendingGestures !== scheduledGesture;
1407
+ }
1408
+ }
1409
+ }
1410
+
1411
if (shouldSkipUpdate) {
1412
// Priority is insufficient. Skip this update. If this is the first
1413
// skipped update, the previous update/state is the new base
1415
const clone: Update<S, A> = {
1416
lane: updateLane,
1417
revertLane: update.revertLane,
1418
+ gesture: update.gesture,
1419
action: update.action,
1420
hasEagerState: update.hasEagerState,
1421
eagerState: update.eagerState,
1451
// this will never be skipped by the check above.
1452
lane: NoLane,
1453
revertLane: NoLane,
1454
+ gesture: null,
1455
action: update.action,
1456
hasEagerState: update.hasEagerState,
1457
eagerState: update.eagerState,
1495
// Reuse the same revertLane so we know when the transition
1496
// has finished.
1497
revertLane: update.revertLane,
1498
+ gesture: null, // If it commits, it's no longer a gesture update.
1499
action: update.action,
1500
hasEagerState: update.hasEagerState,
1501
eagerState: update.eagerState,
2168
// This is a fork of startTransition
2169
const prevTransition = ReactSharedInternals.T;
2170
const currentTransition: Transition = ({}: any);
2171
+ if (enableSwipeTransition) {
2172
+ currentTransition.gesture = null;
2173
+ }
2174
if (enableTransitionTracing) {
2175
currentTransition.name = null;
2176
currentTransition.startTime = -1;
3050
3051
const prevTransition = ReactSharedInternals.T;
3052
const currentTransition: Transition = ({}: any);
3053
+ if (enableSwipeTransition) {
3054
+ currentTransition.gesture = null;
3055
+ }
3056
if (enableTransitionTracing) {
3057
currentTransition.name =
3058
options !== undefined && options.name !== undefined ? options.name : null;
3262
export function requestFormReset(formFiber: Fiber) {
3263
const transition = requestCurrentTransition();
3264
3229
- if (__DEV__) {
3230
- if (transition === null) {
3265
+ if (transition === null) {
3266
+ if (__DEV__) {
3267
// An optimistic update occurred, but startTransition is not on the stack.
3268
// The form reset will be scheduled at default (sync) priority, which
3269
// is probably not what the user intended. Most likely because the
3278
'fix, move to an action, or wrap with startTransition.',
3279
);
3280
}
3281
+ } else if (enableSwipeTransition && transition.gesture) {
3282
+ throw new Error(
3283
+ 'Cannot requestFormReset() inside a startGestureTransition. ' +
3284
+ 'There should be no side-effects associated with starting a ' +
3285
+ 'Gesture until its Action is invoked. Move side-effects to the ' +
3286
+ 'Action instead.',
3287
+ );
3288
}
3289
3290
const stateHook = ensureFormComponentIsStateful(formFiber);
3484
const update: Update<S, A> = {
3485
lane,
3486
revertLane: NoLane,
3487
+ gesture: null,
3488
action,
3489
hasEagerState: false,
3490
eagerState: null,
3544
const update: Update<S, A> = {
3545
lane,
3546
revertLane: NoLane,
3547
+ gesture: null,
3548
action,
3549
hasEagerState: false,
3550
eagerState: null,
3652
}
3653
}
3654
3655
+ // For regular Transitions an optimistic update commits synchronously.
3656
+ // For gesture Transitions an optimistic update commits on the GestureLane.
3657
+ const lane =
3658
+ enableSwipeTransition && transition !== null && transition.gesture
3659
+ ? GestureLane
3660
+ : SyncLane;
3661
const update: Update<S, A> = {
3611
- // An optimistic update commits synchronously.
3612
- lane: SyncLane,
3662
+ lane: lane,
3663
// After committing, the optimistic update is "reverted" using the same
3664
// lane as the transition it's associated with.
3665
revertLane: requestTransitionLane(transition),
3666
+ gesture: null,
3667
action,
3668
hasEagerState: false,
3669
eagerState: null,
3686
}
3687
}
3688
} else {
3638
- const root = enqueueConcurrentHookUpdate(fiber, queue, update, SyncLane);
3689
+ const root = enqueueConcurrentHookUpdate(fiber, queue, update, lane);
3690
if (root !== null) {
3691
// NOTE: The optimistic update implementation assumes that the transition
3692
// will never be attempted before the optimistic update. This currently
3693
// holds because the optimistic update is always synchronous. If we ever
3694
// change that, we'll need to account for this.
3644
- startUpdateTimerByLane(SyncLane);
3645
- scheduleUpdateOnFiber(root, fiber, SyncLane);
3695
+ startUpdateTimerByLane(lane);
3696
+ scheduleUpdateOnFiber(root, fiber, lane);
3697
// Optimistic updates are always synchronous, so we don't need to call
3698
// entangleTransitionUpdate here.
3699
+ if (enableSwipeTransition && transition !== null) {
3700
+ const provider = transition.gesture;
3701
+ if (provider !== null) {
3702
+ // If this was a gesture, ensure we have a scheduled gesture and that
3703
+ // we associate this update with this specific gesture instance.
3704
+ update.gesture = scheduleGesture(root, provider);
3705
+ }
3706
+ }
3707
}
3708
}
3709
3651
- markUpdateInDevTools(fiber, SyncLane, action);
3710
+ markUpdateInDevTools(fiber, lane, action);
3711
}
3712
3713
function isRenderPhaseUpdate(fiber: Fiber): boolean {
3828
? false
3829
: // If no option is specified, imply from the values specified.
3830
queue.initialDirection;
3772
- const scheduledGesture = scheduleGesture(
3831
+ const scheduledGesture = scheduleGestureLegacy(
3832
root,
3833
gestureTimeline,
3834
initialDirection,