-
Notifications
You must be signed in to change notification settings - Fork 4.2k
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
useSelect: improve transition from async to sync mode #40680
Conversation
// initial render + rerender with isAsync=false + store state update | ||
expect( TestComponent ).toHaveBeenCalledTimes( 3 ); | ||
// initial render + rerender with isAsync=false | ||
expect( TestComponent ).toHaveBeenCalledTimes( 2 ); |
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 sounds like a potential performance improvement.
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.
Unfortunately this happens only in a very rare condition where there actually was a pending store update when the component was switching from async to sync mode.
Size Change: -6 B (0%) Total Size: 1.23 MB
ℹ️ View Unchanged
|
This PR refactors
useSelect
code that makes sure that when the component is switching from async to sync mode, then the state updates scheduled while still in async mode won't be forgotten.The old code achieved that by flushing the render queue during the transition, which means synchronously calling
onStoreChange
and reading the new state from stores.The new code reads the new state from stores, too, but does it by doing a
hasLeftAsyncMode
check and callingmapSelect
if the check is true. It's an addition to the set of existing checks that trigger call ofmapSelect
: change of registry, change of themapSelect
function itself (and its dependencies), and failure on previous call.Why is this change for the better? Because it removes a
renderQueue.flush
call, and concentrates allrenderQueue
references into the effect that maintains store subscriptions and calls theonStoreChange
callback. That makes it easier to extract that effect to a separate hook, i.e., finishing the work in #40093.How to test:
Covered by unit tests, namely the "catches updates while switching from async to sync" one. See also #19286 which describes the conditions where doing the async->sync transition incorrectly can lead to UI bugs.