-
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
useDeferredValue should skip initialValue if it suspends #27509
Conversation
1e1d2eb
to
63a171b
Compare
Comparing: 9abf6fa...66267d0 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 |
8999797
to
89e8b89
Compare
if (includesOnlyRetries(workInProgressRootRenderLanes)) { | ||
// Retries are slightly lower priority than transitions, so if Retry task | ||
// spawns a deferred task, the deferred task is also considered a Retry. | ||
workInProgressDeferredLane = claimNextRetryLane(); |
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.
Still thinking about this... I'm not sure it's quite right because elsewhere we assume that a Retry task is only used to fill in Suspense fallbacks.
The only reason I have a special case here is because Retry is lower priority than Transitions, and I wanted to avoid a priority inversion. So it's mostly theoretical.
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.
yeah I'm going to revert this part and spawn as a Transition (like it does today) until I can think of a more compelling reason why it should be different.
I'll leave the Offscreen branch, though.
89e8b89
to
67770c0
Compare
The Deferred lane will be used to mark deferred work that is spawned by useDeferredValue during render. It doesn't have a priority on its own; it will always be entangled with some other lane. That's also why we don't need multiple deferred lanes. We can check for the presence of the Deferred lane to quickly determine if a render was spawned by useDeferredValue.
67770c0
to
508437f
Compare
If a parent render spawns a deferred task with useDeferredValue, but the parent render suspends, we should not wait for the parent render to complete before attempting to render the final value. The reason is that the initialValue argument to useDeferredValue is meant to represent an immediate preview of the final UI. If we can't render it "immediately", we might as well skip it and go straight to the "real" value. This is an improvement over how a userspace implementation of useDeferredValue would work, because a userspace implementation would have to wait for the parent task to commit (useEffect) before spawning the deferred task, creating a waterfall.
508437f
to
66267d0
Compare
### Based on #27505 If a parent render spawns a deferred task with useDeferredValue, but the parent render suspends, we should not wait for the parent render to complete before attempting to render the final value. The reason is that the initialValue argument to useDeferredValue is meant to represent an immediate preview of the final UI. If we can't render it "immediately", we might as well skip it and go straight to the "real" value. This is an improvement over how a userspace implementation of useDeferredValue would work, because a userspace implementation would have to wait for the parent task to commit (useEffect) before spawning the deferred task, creating a waterfall. DiffTrain build for [b2a68a6](b2a68a6)
### Based on #27509 Revealing a prerendered tree (hidden -> visible) is considered the same as mounting a brand new tree. So, when an initialValue argument is passed to useDeferredValue, and it's prerendered inside a hidden tree, we should first prerender the initial value. After the initial value has been prerendered, we switch to prerendering the final one. This is the same sequence that we use when mounting new visible tree. Depending on how much prerendering work has been finished by the time the tree is revealed, we may or may not be able to skip all the way to the final value. This means we get the benefits of both prerendering and preview states: if we have enough resources to prerender the whole thing, we do that. If we don't, we have a preview state to show for immediate feedback.
### Based on #27509 Revealing a prerendered tree (hidden -> visible) is considered the same as mounting a brand new tree. So, when an initialValue argument is passed to useDeferredValue, and it's prerendered inside a hidden tree, we should first prerender the initial value. After the initial value has been prerendered, we switch to prerendering the final one. This is the same sequence that we use when mounting new visible tree. Depending on how much prerendering work has been finished by the time the tree is revealed, we may or may not be able to skip all the way to the final value. This means we get the benefits of both prerendering and preview states: if we have enough resources to prerender the whole thing, we do that. If we don't, we have a preview state to show for immediate feedback. DiffTrain build for [75c1bd7](75c1bd7)
Update React from from 09fbee89d to a41957507. ### React upstream changes - facebook/react#27472 - facebook/react#27512 - facebook/react#27509 - facebook/react#27517 - facebook/react#27523 - facebook/react#27516 - facebook/react#27505
Changes: * fix[devtools/useMemoCache]: add stub for useMemoCache in ReactDebugHook ([hoxyq](https://github.com/hoxyq) in [#27472](#27472)) * useDeferredValue should skip initialValue if it suspends ([acdlite](https://github.com/acdlite) in [#27509](#27509)) * feat[react-devtools-extensions/logging]: initialize session id on the client for logging ([hoxyq](https://github.com/hoxyq) in [#27517](#27517)) * refactor[react-devtools-extensions]: use globals to eliminate dead code ([hoxyq](https://github.com/hoxyq) in [#27516](#27516)) * fix[devtools/inspectElement]: dont pause initial inspectElement call when user switches tabs ([hoxyq](https://github.com/hoxyq) in [#27488](#27488))
) ### Based on facebook#27505 If a parent render spawns a deferred task with useDeferredValue, but the parent render suspends, we should not wait for the parent render to complete before attempting to render the final value. The reason is that the initialValue argument to useDeferredValue is meant to represent an immediate preview of the final UI. If we can't render it "immediately", we might as well skip it and go straight to the "real" value. This is an improvement over how a userspace implementation of useDeferredValue would work, because a userspace implementation would have to wait for the parent task to commit (useEffect) before spawning the deferred task, creating a waterfall.
### Based on facebook#27509 Revealing a prerendered tree (hidden -> visible) is considered the same as mounting a brand new tree. So, when an initialValue argument is passed to useDeferredValue, and it's prerendered inside a hidden tree, we should first prerender the initial value. After the initial value has been prerendered, we switch to prerendering the final one. This is the same sequence that we use when mounting new visible tree. Depending on how much prerendering work has been finished by the time the tree is revealed, we may or may not be able to skip all the way to the final value. This means we get the benefits of both prerendering and preview states: if we have enough resources to prerender the whole thing, we do that. If we don't, we have a preview state to show for immediate feedback.
Changes: * fix[devtools/useMemoCache]: add stub for useMemoCache in ReactDebugHook ([hoxyq](https://github.com/hoxyq) in [facebook#27472](facebook#27472)) * useDeferredValue should skip initialValue if it suspends ([acdlite](https://github.com/acdlite) in [facebook#27509](facebook#27509)) * feat[react-devtools-extensions/logging]: initialize session id on the client for logging ([hoxyq](https://github.com/hoxyq) in [facebook#27517](facebook#27517)) * refactor[react-devtools-extensions]: use globals to eliminate dead code ([hoxyq](https://github.com/hoxyq) in [facebook#27516](facebook#27516)) * fix[devtools/inspectElement]: dont pause initial inspectElement call when user switches tabs ([hoxyq](https://github.com/hoxyq) in [facebook#27488](facebook#27488))
### Based on #27505 If a parent render spawns a deferred task with useDeferredValue, but the parent render suspends, we should not wait for the parent render to complete before attempting to render the final value. The reason is that the initialValue argument to useDeferredValue is meant to represent an immediate preview of the final UI. If we can't render it "immediately", we might as well skip it and go straight to the "real" value. This is an improvement over how a userspace implementation of useDeferredValue would work, because a userspace implementation would have to wait for the parent task to commit (useEffect) before spawning the deferred task, creating a waterfall. DiffTrain build for commit b2a68a6.
### Based on #27509 Revealing a prerendered tree (hidden -> visible) is considered the same as mounting a brand new tree. So, when an initialValue argument is passed to useDeferredValue, and it's prerendered inside a hidden tree, we should first prerender the initial value. After the initial value has been prerendered, we switch to prerendering the final one. This is the same sequence that we use when mounting new visible tree. Depending on how much prerendering work has been finished by the time the tree is revealed, we may or may not be able to skip all the way to the final value. This means we get the benefits of both prerendering and preview states: if we have enough resources to prerender the whole thing, we do that. If we don't, we have a preview state to show for immediate feedback. DiffTrain build for commit 75c1bd7.
Based on #27505
If a parent render spawns a deferred task with useDeferredValue, but the parent render suspends, we should not wait for the parent render to complete before attempting to render the final value.
The reason is that the initialValue argument to useDeferredValue is meant to represent an immediate preview of the final UI. If we can't render it "immediately", we might as well skip it and go straight to the "real" value.
This is an improvement over how a userspace implementation of useDeferredValue would work, because a userspace implementation would have to wait for the parent task to commit (useEffect) before spawning the deferred task, creating a waterfall.