From 8143f1d8ee7f819c97cc610c72c196fc52be5837 Mon Sep 17 00:00:00 2001 From: juliusmarminge Date: Tue, 19 Nov 2024 19:54:12 +0100 Subject: [PATCH 1/2] init --- .../react-next-15/app/client-component.tsx | 16 ++++++++-------- .../react-next-15/app/make-query-client.ts | 1 + packages/query-core/src/types.ts | 6 ++++++ packages/react-query/src/useBaseQuery.ts | 5 +++++ 4 files changed, 20 insertions(+), 8 deletions(-) diff --git a/integrations/react-next-15/app/client-component.tsx b/integrations/react-next-15/app/client-component.tsx index 29dd7b33c9..8a6525310f 100644 --- a/integrations/react-next-15/app/client-component.tsx +++ b/integrations/react-next-15/app/client-component.tsx @@ -1,11 +1,11 @@ 'use client' import React from 'react' -import { useQuery } from '@tanstack/react-query' +import { useQuery, useSuspenseQuery } from '@tanstack/react-query' import { Temporal } from '@js-temporal/polyfill' export function ClientComponent() { - const query = useQuery({ + const query = useSuspenseQuery({ queryKey: ['data'], queryFn: async () => { await new Promise((r) => setTimeout(r, 1000)) @@ -16,13 +16,13 @@ export function ClientComponent() { }, }) - if (query.isPending) { - return
Loading...
- } + // if (query.isPending) { + // return
Loading...
+ // } - if (query.isError) { - return
An error has occurred!
- } + // if (query.isError) { + // return
An error has occurred!
+ // } return (
diff --git a/integrations/react-next-15/app/make-query-client.ts b/integrations/react-next-15/app/make-query-client.ts index 3d0ff40cb8..d970cc22b3 100644 --- a/integrations/react-next-15/app/make-query-client.ts +++ b/integrations/react-next-15/app/make-query-client.ts @@ -26,6 +26,7 @@ export function makeQueryClient() { }, queries: { staleTime: 60 * 1000, + warnOnServerFetches: true, }, dehydrate: { serializeData: tson.serialize, diff --git a/packages/query-core/src/types.ts b/packages/query-core/src/types.ts index b13e52d16c..bb23edce86 100644 --- a/packages/query-core/src/types.ts +++ b/packages/query-core/src/types.ts @@ -223,6 +223,12 @@ export interface QueryOptions< * Maximum number of pages to store in the data of an infinite query. */ maxPages?: number + /** + * If set to `true`, the query will warn if it is fetched on the server. + * Use this if you intend to only consume prefetched queries. + * Defaults to `false`. + */ + warnOnServerFetches?: boolean } export interface InitialPageParam { diff --git a/packages/react-query/src/useBaseQuery.ts b/packages/react-query/src/useBaseQuery.ts index bcbf700ef7..dbe2c22771 100644 --- a/packages/react-query/src/useBaseQuery.ts +++ b/packages/react-query/src/useBaseQuery.ts @@ -111,6 +111,11 @@ export function useBaseQuery< // Handle suspense if (shouldSuspend(defaultedOptions, result)) { + if (defaultedOptions.warnOnServerFetches && isNewCacheEntry) { + console.warn( + 'A new query suspended on the server without any cache entry.', + ) + } throw fetchOptimistic(defaultedOptions, observer, errorResetBoundary) } From 0e5b86c91c21d3eda32cecb86c700dd6b7dae18a Mon Sep 17 00:00:00 2001 From: juliusmarminge Date: Tue, 19 Nov 2024 20:19:48 +0100 Subject: [PATCH 2/2] tesst --- integrations/react-next-15/app/page.tsx | 26 ++--- .../src/__tests__/useSuspenseQuery.test.tsx | 96 +++++++++++++++++++ 2 files changed, 110 insertions(+), 12 deletions(-) diff --git a/integrations/react-next-15/app/page.tsx b/integrations/react-next-15/app/page.tsx index 2382ab540f..df3e51e056 100644 --- a/integrations/react-next-15/app/page.tsx +++ b/integrations/react-next-15/app/page.tsx @@ -1,4 +1,4 @@ -import React from 'react' +import React, { Suspense } from 'react' import { HydrationBoundary, dehydrate } from '@tanstack/react-query' import { Temporal } from '@js-temporal/polyfill' import { ClientComponent } from './client-component' @@ -9,21 +9,23 @@ const sleep = (ms: number) => new Promise((resolve) => setTimeout(resolve, ms)) export default async function Home() { const queryClient = makeQueryClient() - void queryClient.prefetchQuery({ - queryKey: ['data'], - queryFn: async () => { - await sleep(2000) - return { - text: 'data from server', - date: Temporal.PlainDate.from('2024-01-01'), - } - }, - }) + // void queryClient.prefetchQuery({ + // queryKey: ['data'], + // queryFn: async () => { + // await sleep(2000) + // return { + // text: 'data from server', + // date: Temporal.PlainDate.from('2024-01-01'), + // } + // }, + // }) return (
- + Loading...
}> + + ) diff --git a/packages/react-query/src/__tests__/useSuspenseQuery.test.tsx b/packages/react-query/src/__tests__/useSuspenseQuery.test.tsx index 003655ec1d..f235552170 100644 --- a/packages/react-query/src/__tests__/useSuspenseQuery.test.tsx +++ b/packages/react-query/src/__tests__/useSuspenseQuery.test.tsx @@ -903,4 +903,100 @@ describe('useSuspenseQuery', () => { ) consoleErrorSpy.mockRestore() }) + + describe.only("warnOnServerFetches should warn when query isn't prefetched", () => { + it('global default', async () => { + const queryClient = createQueryClient({ + defaultOptions: { + queries: { + warnOnServerFetches: true, + }, + }, + }) + + const consoleWarnSpy = vi + .spyOn(console, 'warn') + .mockImplementation(() => {}) + + function App() { + useSuspenseQuery({ + queryKey: queryKey(), + queryFn: () => Promise.resolve('data1'), + }) + + return null + } + + renderWithClient(queryClient, ) + + expect(consoleWarnSpy).toHaveBeenCalledWith( + 'A new query suspended on the server without any cache entry.', + ) + }) + + it('local override', async () => { + const queryClient = createQueryClient({ + defaultOptions: { + queries: { + warnOnServerFetches: true, + }, + }, + }) + + const consoleWarnSpy = vi + .spyOn(console, 'warn') + .mockImplementation(() => {}) + + function App() { + useSuspenseQuery({ + queryKey: queryKey(), + queryFn: () => Promise.resolve('data1'), + warnOnServerFetches: false, + }) + + return null + } + + renderWithClient(queryClient, ) + + expect(consoleWarnSpy).not.toHaveBeenCalled() + }) + + it('mix of both', async () => { + const queryClient = createQueryClient({ + defaultOptions: { + queries: { + warnOnServerFetches: true, + }, + }, + }) + + const consoleWarnSpy = vi + .spyOn(console, 'warn') + .mockImplementation(() => {}) + + function Component(props: { warnOnServerFetches?: boolean }) { + useSuspenseQuery({ + queryKey: queryKey(), + queryFn: () => Promise.resolve('data'), + warnOnServerFetches: props.warnOnServerFetches, + }) + + return null + } + + function App() { + return ( + <> + + + + ) + } + + renderWithClient(queryClient, ) + + expect(consoleWarnSpy).not.toHaveBeenCalledTimes(1) + }) + }) })