-
Notifications
You must be signed in to change notification settings - Fork 4.3k
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: only invalidate on subscribe if store changed #57108
Changes from 4 commits
1f26294
6147977
ba4764e
a94d977
1631033
211dbd3
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -44,6 +44,7 @@ function Store( registry, suspense ) { | |
let lastIsAsync; | ||
let subscriber; | ||
let didWarnUnstableReference; | ||
let storeStatesOnMount; | ||
|
||
const createSubscriber = ( stores ) => { | ||
// The set of stores the `subscribe` function is supposed to subscribe to. Here it is | ||
|
@@ -61,7 +62,16 @@ function Store( registry, suspense ) { | |
// in the interval between the `getValue` call during render and creating | ||
// the subscription, which is slightly delayed. We need to ensure that this | ||
// second `getValue` call will compute a fresh value. | ||
lastMapResultValid = false; | ||
lastMapResultValid = | ||
activeStores.length === storeStatesOnMount.length && | ||
activeStores.every( | ||
( storeName, index ) => | ||
storeStatesOnMount[ index ] === | ||
// To do: figure out why it's sometimes not available in | ||
// unit tests. | ||
registry.stores[ storeName ]?.store?.getState?.() | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @jsnajdr @youknowriad Any idea why this is not available in some unit tests? Something about custom generic stores? Is there a better way to may store names to their state? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes, custom generic stores. The things in I'm curious if this state comparison is still a performance optimization, as it's a completely different approach than the original There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It should be, the graph looks the same as the other optimisation There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Getting -6.75% for first block load in this run. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I guess if there's no interface, we can always return false for now (previous behaviour). But strange that there's no way to get the state. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm thinking we could add an optional There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Should we try that separately? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Fine with it. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Second run after the rewrite is 6.6% for first block load There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Yes, and to prevent misuse to read private-ish data, return an empty object |
||
); | ||
storeStatesOnMount = null; | ||
|
||
const onStoreChange = () => { | ||
// Invalidate the value on store update, so that a fresh value is computed. | ||
|
@@ -149,6 +159,9 @@ function Store( registry, suspense ) { | |
} | ||
|
||
if ( ! subscriber ) { | ||
storeStatesOnMount = listeningStores.current.map( ( name ) => | ||
registry.stores[ name ]?.store?.getState?.() | ||
); | ||
subscriber = createSubscriber( listeningStores.current ); | ||
} else { | ||
subscriber.updateStores( listeningStores.current ); | ||
|
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.
The
subscribe
function could be called multiple times to obtain multiple subscriptions. React probably never does it, but it's a reasonable operation anyway. Here, the secondsubscribe
call will dereference anull
object and crash.By the way, what if
storeStatesOnMount
was an object keyed by store name? Seems better than array to me.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.
Yes, that's true, a Map is cleaner and also solves the other issue.