TanStack / query

🤖 Powerful asynchronous state management, server-state utilities and data fetching for the web. TS/JS, React Query, Solid Query, Svelte Query and Vue Query.
https://tanstack.com/query
MIT License
41.72k stars 2.84k forks source link

The queryClient is made reactive (!?) in the options causing severe performance issues in vue #5031

Closed simonwep closed 1 year ago

simonwep commented 1 year ago

Describe the bug

Hey! We make extensive use of the query client by, for example, using a query in a table to resolve a value for each cell. We also initialize our own instance of QueryClient and pass it as option to each useXXX-call like so:

const queryClient = new QueryClient({ ... });
const query = useQuery(..., ..., {
    queryClient,
});

We have to do this since we use the query-client outside of vue component-instances and, as of right now, the query client is by default injected which would throw an error in this instance.

For some reason the queryClient seems to be made reactive as this causes severe performance issues in our case since vue traverses the whole client for reactive changes on every change.

Your minimal, reproducible example

See below

Steps to reproduce

I unfortunately couldn't manage to reproduce it as this seems to only happen if there is lots of data so please bear with me. I seem to have found out what might cause performance issues with the new option of passing the queryClient to, for example, useQuery:

All arguments passed to useQuery (and other utility functions) are wrapped in a computed, cloned and refs unwrapped. This includes the queryClient we pass as option as well. Now, the query client is rather large and, I'm not sure, may contain many reactive values / data-structures which are cloned every time they change (because of the computed).

When we mark the queryClient as raw all problems are gone, the same if we do not pass the queryClient directly as option to one of the query functions.

This issue is difficult to reproduce, as on our end we work with very large amount of dynamic queries (e.g. queries where the query key changes), that is around 200-10.000, and for anything below that JavaScript is fast enough to process the whole queryClient as you do.

Expected behavior

The queryClient should not be cloned or made reactive (at least not as it's done right now). Instead, you could extract the queryClient from the options (here?!) and handle it separately which would solve the issue.

How often does this bug happen?

Every time

Screenshots or Videos

Performance tests conducted on our system (closed source) with only one change: marking the queryClient as raw or not passing it as option:

passing the queryClient as-is to useQuery:
image

marking the queryClient as raw or not providing it as option in useQuery:
image

I know that this doesn't really help as I can't share my code with you for this, but just to demonstrate the difference it makes for us with this little change)-

Platform

Also happens on comparable windows / mac-os setups.

TanStack Query version

v4.24.6

TypeScript version

v4.9.5

Additional context

I'm sorry that I couldn't come up with a reproduction, if there are any more details I can add to help fix this please go ahead. I tried to provide as many details as possible, but the project I'm working on is rather large and closed-source making it difficult to create an appropriate reproduction.

DamianOsipiuk commented 1 year ago

Hi This problem will be solved in v5 as queryClient will be passed as a separate option https://github.com/TanStack/query/blob/alpha/packages/vue-query/src/useBaseQuery.ts#L66

As for v4, maybe extracting client in parseQueryArgs to prevent deep cloning, would be enough?

DamianOsipiuk commented 1 year ago

Should be fixed in https://github.com/TanStack/query/releases/tag/v4.32.2