-
Notifications
You must be signed in to change notification settings - Fork 47k
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
Add end-of-frame scheduling for default events #24594
Conversation
It's the same as any other setState. Shouldn't need to do anything special.
Don't need to for our tests unless we're testing the behavior of React DOM specifically. In the open source build, people will either use
Nah I can't think of any reason why it should
Sounds right to me, that's where
The only place in the reconciler where there should be a fork in behavior is in
The main ones I can think of are
|
Thanks for all the answers @acdlite!
My bad, I must have misheard that we wanted a separate lane. I'll switch this to a FiberRoot flag 👍
When |
Yeah I think so |
3fd61cb
to
1ab4eaa
Compare
Comparing: 8186b19...7d03b23 Critical size changesIncludes critical production bundles, as well as any change greater than 2%:
Significant size changesIncludes any change greater than 0.2%: Expand to show
|
f171cfb
to
10483f6
Compare
I believe this is ready for another review 🤝 |
newCallbackPriority === DefaultLane && | ||
existingFrameAlignedNode == null && | ||
typeof window !== 'undefined' && | ||
typeof window.event === 'undefined' |
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.
This logic needs to move to the Host Config because it's DOM-specific.
}); | ||
expect(Scheduler).toHaveYielded(['Count: 0']); | ||
|
||
window.event = 'test'; |
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.
Nit: I would use an actual DOM event here. Like with dispatchEvent
.
1790519
to
3d41b27
Compare
packages/react-reconciler/README.md
Outdated
@@ -210,6 +210,17 @@ Set this to true to indicate that your renderer supports `scheduleMicrotask`. We | |||
|
|||
Optional. You can proxy this to `queueMicrotask` or its equivalent in your environment. | |||
|
|||
#### `supportsFrameEndTask` |
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.
thanks
82daf47
to
0d53dba
Compare
newCallbackPriority === DefaultLane && | ||
root.hasUnknownUpdates | ||
) { | ||
// Do nothing, we need to cancel the existing default task and schedule a rAF. |
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.
This seems wrong because what if a rAF were already scheduled? It would cancel it and schedule a new one, which might cause us to get shifted into a later frame
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.
Ah yeah, good point. I'll update.
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.
@acdlite so when should we cancel the raf and scheduler task in this case? If we don't cancel here, we'll orphan existingCallbackNode
without canceling the task. One option is to cancel it only if the newCallbackPriority
is not default. That could push things to the next frame if something higher priority comes in like a click, but may be desirable so that the sync microtask fires first anyway?
0d53dba
to
f346a1f
Compare
// requestAnimationFrame | ||
// ------------------- | ||
export const supportsFrameEndTask = true; | ||
export function scheduleFrameEndTask(task) { |
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.
I think "frame aligned" is better than "frame end", it doesn't matters where it fires in the refresh cycle as long as it happens before the next paint
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.
Done
c54e365
to
0a0565e
Compare
0a0565e
to
e012516
Compare
Closing because I think the unified sync lane stuff replaces this. |
Overview
This PR schedules a second task for default updates at the end of the frame when we cannot determine the priority of the originating event. These updates include things like
IntersectionObserver
,ResizeObserver
,setTimeout
, or any other event wherewindow.event
is undefined.These updates are flushed inside
requestAnimationFrame
in addition to the task, so that updates scheduled inside of things likeResizeObservers
have an opportunity to flush before the next repaint. We'll use whichever task fires first.TODO Incomplete
supportsAnimationFrame
,scheduleAnimationFrame
, andcancelAnimationFrame
TODO Questions
root.render
orhydrateRoot
?requestAnimationFrame
(it doesn't flush with timers in jsdom)?internalAct
.ReactNoopRenderer
include arAF
mock?scheduleAnimationFrame
likeschedulePostTask