-
-
Notifications
You must be signed in to change notification settings - Fork 2.8k
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
feat: add support for React.use()
#7988
base: main
Are you sure you want to change the base?
Conversation
☁️ Nx Cloud ReportCI is running/has finished running commands for commit b573cc6. As they complete they will appear below. Click to see the status, the terminal output, and the build insights. 📂 See all runs for this CI Pipeline Execution ✄1�7 Successfully ran 2 targetsSent with 💌 from NxCloud. |
More templates
@tanstack/angular-query-devtools-experimental
@tanstack/angular-query-experimental
@tanstack/eslint-plugin-query
@tanstack/query-broadcast-client-experimental
@tanstack/query-async-storage-persister
@tanstack/query-core
@tanstack/query-devtools
@tanstack/query-persist-client-core
@tanstack/query-sync-storage-persister
@tanstack/react-query-devtools
@tanstack/react-query
@tanstack/react-query-next-experimental
@tanstack/react-query-persist-client
@tanstack/solid-query
@tanstack/solid-query-devtools
@tanstack/solid-query-persist-client
@tanstack/svelte-query
@tanstack/svelte-query-devtools
@tanstack/vue-query
@tanstack/svelte-query-persist-client
@tanstack/vue-query-devtools
commit: |
This comment was marked as outdated.
This comment was marked as outdated.
ec583d5
to
8cbd6a0
Compare
This comment was marked as outdated.
This comment was marked as outdated.
|
I made two changes:
|
|
cc @tkodo I've updated it so it's behind a feature flag now |
|
I will talk with @Ephem about this next week |
|
I added some more tests where I wasn't sure if that will work, but it does 👏 . I will discuss this PR with @Ephem next week but I think we can ship it then. I might want to rename the feature flag to |
|
So I made some more tests for normal with the flag on, the two logged timestamps consistently differ by 2ms, because we start the fetch immediately. with the flag off, we start the fetch in the uSES subscription / an effect, which can be later, depending on how intensive rendering is. In this little example, it was usually 4-5ms. However, if we add a bit of cpu intensive work to our component, like rendering 1k divs: the delay was around 30ms, but obviously still a constant 2ms with the flag on. This probably doesn't matter if your fetch takes 500ms, but I've just had a discussion with someone who said their fetches were delayed by 1-3 seconds, and it turns out it was something in their component rendering. So the question is: is this actually a good optimization for normal |
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.
Fantastic! 👏👏 This is pretty complex, so I'll need to some more time to really wrap my head around things.
So many great tests here! Do you think it would make sense to also add some tests with <HydrationBoundary>, both when we de/rehydrate already awaited data, and when we de/rehydrate a promise?
| !observer.hasListeners() | ||
| ) { | ||
| const promise = isNewCacheEntry | ||
| ? // Fetch immediately on mount in order to ensure `.promise` is resolved even if the component is unmounted |
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: This comment has me a bit confused, is it "in render" instead of "on mount"?
| client.getQueryCache().get(defaultedOptions.queryHash)?.promise | ||
|
|
||
| promise?.catch(noop).finally(() => { | ||
| if (!observer.hasListeners()) { |
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'm trying to wrap my head around this all. Why are we checking for !observer.hasListeners() here?
| @@ -82,6 +85,13 @@ export class QueryObserver< | |||
|
|
|||
| this.#client = client | |||
| this.#selectError = null | |||
| this.#currentThenable = pendingThenable() | |||
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 just want to double check that I'm thinking about this correctly. This is a "proxy"-thenable that is kept in sync with the promise that lives in the query cache, and the mechanism for that "syncing" is the updateResult-function?
So any means of resolving, rejecting or replacing the original promise needs to call updateResult on all observers to "sync" to the thenables?
Just thinking out loud, this makes me wonder what happens if you:
- useQuery -> use(promise)
- fetchQuery / refetch before above query resolves, and either:
- The first query resolves first
- The fetchQuery / refetch resolves first
Does this have a defined behaviour? I'm not even sure what should happen. 😅
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.
we can add tests for this, but the way I see it, fetchQuery would just pick up the promise that's already running and not start a new fetch. Of course, if you do queryClient.refetchQueries and target this key, it would cancel the ongoing fetch per default. Not sure what would happen then, cancel should silently rollback to the previous (pending) state, so maybe it would hang forever.
Definitely interesting case that's worth a couple of tests 👍
I think I need to marinate this a bit. I mean, on one hand it should be "safe" to do. On the other, is it always desirable? I'm thinking about (future) cases like pre-rendering, the If there are any issues there, I fully expect |
yes, this auto_prefetching was pretty much taken from the |
| @@ -82,6 +85,13 @@ export class QueryObserver< | |||
|
|
|||
| this.#client = client | |||
| this.#selectError = null | |||
| this.#currentThenable = pendingThenable() | |||
| if (!this.options.experimental_promise) { | |||
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.
let's rename to: experimental_prefetchInRender
Closes #7980
Progress
useQuery()useInfiniteQuery()