From 700d8542bd1ee7637bf9067476aee526bc2ac180 Mon Sep 17 00:00:00 2001 From: ShiroKSH Date: Wed, 29 Jul 2026 13:39:58 +0300 Subject: [PATCH] fix(react-query): keep unsubscribed useQueries idle --- .changeset/tidy-pandas-wait.md | 5 ++++ .../src/__tests__/useQueries.test.tsx | 28 +++++++++++++++++++ packages/react-query/src/useQueries.ts | 9 ++++-- 3 files changed, 39 insertions(+), 3 deletions(-) create mode 100644 .changeset/tidy-pandas-wait.md diff --git a/.changeset/tidy-pandas-wait.md b/.changeset/tidy-pandas-wait.md new file mode 100644 index 00000000000..c74df8608d1 --- /dev/null +++ b/.changeset/tidy-pandas-wait.md @@ -0,0 +1,5 @@ +--- +'@tanstack/react-query': patch +--- + +fix(react-query): don't show optimistic fetching for unsubscribed useQueries diff --git a/packages/react-query/src/__tests__/useQueries.test.tsx b/packages/react-query/src/__tests__/useQueries.test.tsx index c7a9283d07c..ca5e5251801 100644 --- a/packages/react-query/src/__tests__/useQueries.test.tsx +++ b/packages/react-query/src/__tests__/useQueries.test.tsx @@ -63,6 +63,34 @@ describe('useQueries', () => { expect(results[2]).toMatchObject([{ data: 1 }, { data: 2 }]) }) + it('should not optimistically show fetching when unsubscribed', () => { + const key = queryKey() + const queryFn = vi.fn(() => Promise.resolve('data')) + + function Page() { + const [query] = useQueries({ + queries: [{ queryKey: key, queryFn }], + subscribed: false, + }) + + return ( +
+ isFetching: {String(query.isFetching)} + fetchStatus: {query.fetchStatus} +
+ ) + } + + const rendered = renderWithClient(queryClient, ) + + expect(queryFn).not.toHaveBeenCalled() + expect( + queryClient.getQueryCache().find({ queryKey: key })!.observers.length, + ).toBe(0) + rendered.getByText('isFetching: false') + rendered.getByText('fetchStatus: idle') + }) + it('should track results', async () => { const key1 = queryKey() const results: Array> = [] diff --git a/packages/react-query/src/useQueries.ts b/packages/react-query/src/useQueries.ts index 5f5261a870e..437718a988f 100644 --- a/packages/react-query/src/useQueries.ts +++ b/packages/react-query/src/useQueries.ts @@ -223,6 +223,7 @@ export function useQueries< const client = useQueryClient(queryClient) const isRestoring = useIsRestoring() const errorResetBoundary = useQueryErrorResetBoundary() + const subscribed = options.subscribed !== false const defaultedQueries = React.useMemo( () => @@ -234,11 +235,13 @@ export function useQueries< // Make sure the results are already in fetching state before subscribing or updating options defaultedOptions._optimisticResults = isRestoring ? 'isRestoring' - : 'optimistic' + : subscribed + ? 'optimistic' + : undefined return defaultedOptions }), - [queries, client, isRestoring], + [queries, client, isRestoring, subscribed], ) defaultedQueries.forEach((queryOptions) => { @@ -265,7 +268,7 @@ export function useQueries< (options as QueriesObserverOptions).combine, ) - const shouldSubscribe = !isRestoring && options.subscribed !== false + const shouldSubscribe = !isRestoring && subscribed React.useSyncExternalStore( React.useCallback( (onStoreChange) =>