-
Notifications
You must be signed in to change notification settings - Fork 48.6k
useTransition improvements #17411
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
useTransition improvements #17411
Conversation
The `isPending` state managed by the `useTransition` queue can be modeled using the same queue as useState/useReducer; that's how it's implemented today. However, since there's only ever a single pending transition per `useTransition` hook, and the most recent one always wins, we don't really need to maintain an entire queue structure. This replaces the internal `useState` queue with a specialized implementation. It tracks the most recent transition expiration time on shared instance object, and the last processed expiration time on each hook copy. When the processed expiration time catches up to the pending one, we know that the transition is no longer pending. At a high level, this is also how the `useState` queue works, but without the overhead of an actual queue. The implementation is also inspired by Suspense boundaries, which also have an internal state for whether the boundary is displaying a fallback, but does not use an actual queue to manage that state.
When multiple transitions update the same queue, only the most recent one should be considered pending. Example: If I switch tabs multiple times, only the last tab I click should display a pending state (e.g. an inline spinner).
Details of bundled changes.Comparing: a7d07ff...162454b react-dom
react-native-renderer
react-test-renderer
react-art
react-reconciler
ReactDOM: size: 0.0%, gzip: 0.0% Size changes (experimental) |
Details of bundled changes.Comparing: a7d07ff...162454b react-reconciler
react-dom
react-art
react-test-renderer
react-native-renderer
ReactDOM: size: 🔺+1.2%, gzip: 🔺+1.7% Size changes (stable) |
ce6ac38
to
10ea752
Compare
When multiple transitions update the same queue, only the most recent one should be allowed to finish. Do not display intermediate states. For example, if you click on multiple tabs in quick succession, we should not switch to any tab that isn't the last one you clicked.
@@ -1299,6 +1309,16 @@ function handleError(root, thrownValue) { | |||
stopProfilerTimerIfRunningAndRecordDelta(workInProgress, true); | |||
} | |||
|
|||
// TODO: I think it's fine to use instanceof here because this exception | |||
// is always thrown by the renderer? Or use a brand check. | |||
if (thrownValue instanceof SuspendOnTask) { |
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.
@sebmarkbage I assume you won't like this but I legit don't know what the best approach is. A brand check seems unnecessary since this is always thrown by the renderer and not across realms or packages.
For some reason the CodeSandbox CI job didn't run? Perhaps because I opened it as a draft? I'm going to close and re-open to see if that works. |
(I closed and and re-opened this as #17418)