-
Notifications
You must be signed in to change notification settings - Fork 49.2k
Add Commit Scaffolding for Gestures #32451
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
494d8c5
to
d34f350
Compare
d34f350
to
2487830
Compare
797c1fb
to
9afbc08
Compare
9afbc08
to
23cc8c7
Compare
); | ||
// We must have already cancelled this gesture before we had a chance to | ||
// render it. Let's schedule work on the next set of lanes. | ||
ensureRootIsScheduled(root); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What work is scheduled here if the gesture was never rendered?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There can be lower priority work like Idle or Transition that are now unblocked and can start rendering. Those may not have a callback yet.
@@ -3879,6 +3998,8 @@ function releaseRootPooledCache(root: FiberRoot, remainingLanes: Lanes) { | |||
|
|||
export function flushPendingEffects(wasDelayedCommit?: boolean): boolean { | |||
// Returns whether passive effects were flushed. | |||
flushGestureMutations(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we need to call this separately if its also called at the start of flushGestureAnimations
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not really today but this may not keep being the case that flushGestureAnimations
calls it. I think these will change a bit so that flushGestureAnimations
might be able to be skipped or flushed out of band from other flushes. This just ensures that each step is called regardless.
This phase also collects the appearing side of pairs.
Essentially ReactFiberApplyGesture works as a fork of ReactFiberCommitWork which has its own phase that don't really commit but emulate what a commit into the destination state would look like before getting reverted. This is all done within a startViewTransition. To handle any sync flushing that happens in the gaps of startViewTransition callbacks, we use the same pendingEffectsStatus strategy except with a different sequence. If flushPendingEffects is called early it just goes through it as normal. However it probably should just abort the transition instead.
Instead of relying on the protocol working for both in every environment. This lets us specialize this for gestures. Notably we don't wait for pending navigations or fonts in this mode. Any added fonts would be added before we have a chance to take a snapshot so we don't really have that option here. It's probably fine because most cases for swipe are backwards but it can potentially be an issue swiping into a new page that has new fonts.
I'm about to add another queue.
If we have any scheduled work up until that point, we wait for it to commit first so that if the new commit is the same as the target we don't snap back first.
We need this for the scroll to keep responding to events.
This ensures that we have already scheduled some work before we cancel. That way we know that this work will be the one to commit the new state. Otherwise we might cancel too soon.
If we cancel a gesture before it has a chance to commit we still leave the lane In this case we need to just skip it.
It won't block this transition from completing but it'll stick around to future transitions.
23cc8c7
to
4c5d858
Compare
This adds a `ReactFiberApplyGesture` which is basically intended to be a fork of the phases in `ReactFiberCommitWork` except for the fake commit that `useSwipeTransition` does. So far none of the phases are actually implemented yet. This is just the scaffolding around them so I can fill them in later. The important bit is that we call `startViewTransition` (via the `startGestureTransition` Config) when a gesture starts. We add a paused animation to prevent the transition from committing (even if the ScrollTimeline goes to 100%). This also locks the documents so that we can't commit any other Transitions until it completes. When the gesture completes (scroll end) then we stop the gesture View Transition. If there's no new work scheduled we do that immediately but if there was any new work already scheduled, then we assume that this will potentially commit the new state. So we wait for that to finish. This lets us lock the animation in its state instead of snapping back and then applying the real update. Using this technique we can't actually run a View Transition from the current state to the actual committed state because it would snap back to the beginning and then run the View Transition from there. Therefore any new commit needs to skip View Transitions even if it should've technically animated to that state. We assume that the new state is the same as the optimistic state you already swiped to. An alternative to this technique could be to commit the optimistic state when we cancel and then apply any new updates o top of that. I might explore that in the future. Regardless it's important that the `action` associated with the swipe schedules some work before we cancel. Otherwise it risks reverting first. So I had to update this in the fixture. DiffTrain build for [3607f48](3607f48)
This adds a `ReactFiberApplyGesture` which is basically intended to be a fork of the phases in `ReactFiberCommitWork` except for the fake commit that `useSwipeTransition` does. So far none of the phases are actually implemented yet. This is just the scaffolding around them so I can fill them in later. The important bit is that we call `startViewTransition` (via the `startGestureTransition` Config) when a gesture starts. We add a paused animation to prevent the transition from committing (even if the ScrollTimeline goes to 100%). This also locks the documents so that we can't commit any other Transitions until it completes. When the gesture completes (scroll end) then we stop the gesture View Transition. If there's no new work scheduled we do that immediately but if there was any new work already scheduled, then we assume that this will potentially commit the new state. So we wait for that to finish. This lets us lock the animation in its state instead of snapping back and then applying the real update. Using this technique we can't actually run a View Transition from the current state to the actual committed state because it would snap back to the beginning and then run the View Transition from there. Therefore any new commit needs to skip View Transitions even if it should've technically animated to that state. We assume that the new state is the same as the optimistic state you already swiped to. An alternative to this technique could be to commit the optimistic state when we cancel and then apply any new updates o top of that. I might explore that in the future. Regardless it's important that the `action` associated with the swipe schedules some work before we cancel. Otherwise it risks reverting first. So I had to update this in the fixture. DiffTrain build for [3607f48](3607f48)
This adds a
ReactFiberApplyGesture
which is basically intended to be a fork of the phases inReactFiberCommitWork
except for the fake commit thatuseSwipeTransition
does. So far none of the phases are actually implemented yet. This is just the scaffolding around them so I can fill them in later.The important bit is that we call
startViewTransition
(via thestartGestureTransition
Config) when a gesture starts. We add a paused animation to prevent the transition from committing (even if the ScrollTimeline goes to 100%). This also locks the documents so that we can't commit any other Transitions until it completes.When the gesture completes (scroll end) then we stop the gesture View Transition. If there's no new work scheduled we do that immediately but if there was any new work already scheduled, then we assume that this will potentially commit the new state. So we wait for that to finish. This lets us lock the animation in its state instead of snapping back and then applying the real update.
Using this technique we can't actually run a View Transition from the current state to the actual committed state because it would snap back to the beginning and then run the View Transition from there. Therefore any new commit needs to skip View Transitions even if it should've technically animated to that state. We assume that the new state is the same as the optimistic state you already swiped to. An alternative to this technique could be to commit the optimistic state when we cancel and then apply any new updates o top of that. I might explore that in the future.
Regardless it's important that the
action
associated with the swipe schedules some work before we cancel. Otherwise it risks reverting first. So I had to update this in the fixture.