Skip to content
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

Open
wants to merge 107 commits into
base: main
Choose a base branch
from

Conversation

KATT
Copy link
Contributor

@KATT KATT commented Aug 30, 2024

Closes #7980


Progress

  • add basic functionality for useQuery()
  • make other tests pass (👋 help wanted!)
  • add test for useInfiniteQuery()
  • do more tests with some example
  • update docs?

Copy link

nx-cloud bot commented Aug 30, 2024

☁️ Nx Cloud Report

CI is running/has finished running commands for commit 954d85b. 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


✅ Successfully ran 2 targets

Sent with 💌 from NxCloud.

Copy link

pkg-pr-new bot commented Aug 30, 2024

Open in Stackblitz

More templates

@tanstack/angular-query-devtools-experimental

pnpm add https://pkg.pr.new/@tanstack/angular-query-devtools-experimental@7988

@tanstack/eslint-plugin-query

pnpm add https://pkg.pr.new/@tanstack/eslint-plugin-query@7988

@tanstack/angular-query-experimental

pnpm add https://pkg.pr.new/@tanstack/angular-query-experimental@7988

@tanstack/query-async-storage-persister

pnpm add https://pkg.pr.new/@tanstack/query-async-storage-persister@7988

@tanstack/query-broadcast-client-experimental

pnpm add https://pkg.pr.new/@tanstack/query-broadcast-client-experimental@7988

@tanstack/query-core

pnpm add https://pkg.pr.new/@tanstack/query-core@7988

@tanstack/query-persist-client-core

pnpm add https://pkg.pr.new/@tanstack/query-persist-client-core@7988

@tanstack/query-devtools

pnpm add https://pkg.pr.new/@tanstack/query-devtools@7988

@tanstack/query-sync-storage-persister

pnpm add https://pkg.pr.new/@tanstack/query-sync-storage-persister@7988

@tanstack/react-query

pnpm add https://pkg.pr.new/@tanstack/react-query@7988

@tanstack/react-query-next-experimental

pnpm add https://pkg.pr.new/@tanstack/react-query-next-experimental@7988

@tanstack/react-query-devtools

pnpm add https://pkg.pr.new/@tanstack/react-query-devtools@7988

@tanstack/react-query-persist-client

pnpm add https://pkg.pr.new/@tanstack/react-query-persist-client@7988

@tanstack/solid-query

pnpm add https://pkg.pr.new/@tanstack/solid-query@7988

@tanstack/solid-query-devtools

pnpm add https://pkg.pr.new/@tanstack/solid-query-devtools@7988

@tanstack/solid-query-persist-client

pnpm add https://pkg.pr.new/@tanstack/solid-query-persist-client@7988

@tanstack/svelte-query

pnpm add https://pkg.pr.new/@tanstack/svelte-query@7988

@tanstack/svelte-query-devtools

pnpm add https://pkg.pr.new/@tanstack/svelte-query-devtools@7988

@tanstack/svelte-query-persist-client

pnpm add https://pkg.pr.new/@tanstack/svelte-query-persist-client@7988

@tanstack/vue-query

pnpm add https://pkg.pr.new/@tanstack/vue-query@7988

@tanstack/vue-query-devtools

pnpm add https://pkg.pr.new/@tanstack/vue-query-devtools@7988

commit: 954d85b

@KATT

This comment was marked as outdated.

@KATT

This comment was marked as outdated.

Copy link
Collaborator

@Ephem Ephem left a 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?

packages/react-query/src/useBaseQuery.ts Outdated Show resolved Hide resolved
client.getQueryCache().get(defaultedOptions.queryHash)?.promise

promise?.catch(noop).finally(() => {
if (!observer.hasListeners()) {
Copy link
Collaborator

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?

Copy link
Contributor Author

@KATT KATT Sep 17, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just to prevent updateResult() to be called twice - if it has listeners, updateResult will be called

(It will work without this check too 🤷‍♂️)

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yeah I just checked, if we remove both checks for !observer.hasListeners(), all the tests still pass. if we want to keep these checks, we should add tests where this fails @KATT. I know that calling updateResult multiple times might e.g. re-run inline select functions, but I'm not sure if that's worth optimizing for ...

Copy link
Contributor Author

@KATT KATT Sep 20, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I tried adding a test for it by

vi.spyOn(QueryObserver.prototype, 'updateResult')

but it's called a bunch of times within a render so adding a test [that won't break randomly when changing other things] the way I thought it will be quite hard

feel free to delete the optimization

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've deleted the first check, because it's technically impossible that willFetch is true and we have an observer. I've kept the second check because maybe an observer shows up in between: a9148ba

packages/query-core/src/retryer.ts Outdated Show resolved Hide resolved
packages/query-core/src/queryObserver.ts Show resolved Hide resolved
@Ephem
Copy link
Collaborator

Ephem commented Sep 16, 2024

Thoughts @Ephem ?

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 <Offscreen> API etc. Probably? But maybe not if a router prerenders all possible routes based on Links on a page? Will devs need some more control (prefetch, but not if this is a prerender).

If there are any issues there, I fully expect usePrefetchQuery to have the same ones, but at least that's more explicit. I think that's mostly an argument for not aiming to make this the "default" behaviour though and a big part of me wants to say this is a nice little optimisation and we can tackle any challenges when they come up. 😄

@TkDodo
Copy link
Collaborator

TkDodo commented Sep 16, 2024

If there are any issues there, I fully expect usePrefetchQuery to have the same ones

yes, this auto_prefetching was pretty much taken from the usePrefetchQuery implementation. I think we are aligned that we could keep it as an experimental flag though, and that you need to turn it on to be able to use(promise), which makes the whole promise feature experimental, too :)

@KATT
Copy link
Contributor Author

KATT commented Sep 17, 2024

Ping me know if you need anything on my end here or have questions that I can help answer, I don't see much tangible feedback as of yet ☺

@TkDodo
Copy link
Collaborator

TkDodo commented Sep 18, 2024

This user-land implementation got me thinking: why don't we also do the promise handling in the react layer rather than the observer 🤔. It looks way simplified. What am I missing 😂?

https://github.com/nucleartux/react-query-read

@TkDodo
Copy link
Collaborator

TkDodo commented Sep 18, 2024

@KATT I added more tests, and one scenario is failing (this one): if we cancel the query while we are suspending, we stay in a forever pending state.

I think the problem is that we just revert to the previous state if we get a query cancelation, and state happens to be status: 'pending' because we didn't have any previous data:

if (isCancelledError(error) && error.revert && this.#revertState) {
return { ...this.#revertState, fetchStatus: 'idle' }
}

I'm not even sure rejecting the promise the right expectation here, as the query isn't in error state. Honestly not sure what should happen here - maybe staying in pending is the right call, idk ...

@KATT
Copy link
Contributor Author

KATT commented Sep 18, 2024

@KATT I added more tests, and one scenario is failing (this one): if we cancel the query while we are suspending, we stay in a forever pending state.

I think the problem is that we just revert to the previous state if we get a query cancelation, and state happens to be status: 'pending' because we didn't have any previous data:

if (isCancelledError(error) && error.revert && this.#revertState) {
return { ...this.#revertState, fetchStatus: 'idle' }
}

I'm not even sure rejecting the promise the right expectation here, as the query isn't in error state. Honestly not sure what should happen here - maybe staying in pending is the right call, idk ...

Good catch. Not sure what the right approach here is. I've never cancelled a query and don't see why I would ever do that 😅, but I understand people will use it and break it.

Hm.

I thiiiiiink rejecting it with an AbortError would make sense to me?

@KATT

This comment was marked as outdated.

@KATT

This comment was marked as outdated.

@KATT KATT requested a review from TkDodo September 19, 2024 09:30
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants