diff --git a/packages/angular-query-experimental/src/inject-mutation.ts b/packages/angular-query-experimental/src/inject-mutation.ts index 4ec2c304b9..27d0b6b3fd 100644 --- a/packages/angular-query-experimental/src/inject-mutation.ts +++ b/packages/angular-query-experimental/src/inject-mutation.ts @@ -8,11 +8,11 @@ import { runInInjectionContext, signal, } from '@angular/core' -import { MutationObserver, notifyManager } from '@tanstack/query-core' +import { MutationObserver, noop, notifyManager } from '@tanstack/query-core' import { assertInjector } from './util/assert-injector/assert-injector' import { signalProxy } from './signal-proxy' import { injectQueryClient } from './inject-query-client' -import { noop, shouldThrowError } from './util' +import { shouldThrowError } from './util' import { lazyInit } from './util/lazy-init/lazy-init' import type { diff --git a/packages/angular-query-experimental/src/util/index.ts b/packages/angular-query-experimental/src/util/index.ts index d07a9316fe..0ca9d8fe55 100644 --- a/packages/angular-query-experimental/src/util/index.ts +++ b/packages/angular-query-experimental/src/util/index.ts @@ -1,3 +1,8 @@ +/** + * + * @param throwError + * @param params + */ export function shouldThrowError) => boolean>( throwError: boolean | T | undefined, params: Parameters, @@ -9,5 +14,3 @@ export function shouldThrowError) => boolean>( return !!throwError } - -export function noop() {} diff --git a/packages/query-core/src/index.ts b/packages/query-core/src/index.ts index 0d6dd2f264..56c4f64c37 100644 --- a/packages/query-core/src/index.ts +++ b/packages/query-core/src/index.ts @@ -15,6 +15,7 @@ export { focusManager } from './focusManager' export { onlineManager } from './onlineManager' export { hashKey, + noop, replaceEqualDeep, isServer, matchQuery, diff --git a/packages/query-core/src/utils.ts b/packages/query-core/src/utils.ts index f84fdcd775..41f8289589 100644 --- a/packages/query-core/src/utils.ts +++ b/packages/query-core/src/utils.ts @@ -68,9 +68,7 @@ export type QueryTypeFilter = 'all' | 'active' | 'inactive' export const isServer = typeof window === 'undefined' || 'Deno' in globalThis -export function noop(): undefined { - return undefined -} +export function noop(): undefined {} export function functionalUpdate( updater: Updater, diff --git a/packages/react-query/src/__tests__/suspense.test.tsx b/packages/react-query/src/__tests__/suspense.test.tsx index f13164b1b0..203a89e02d 100644 --- a/packages/react-query/src/__tests__/suspense.test.tsx +++ b/packages/react-query/src/__tests__/suspense.test.tsx @@ -90,7 +90,7 @@ describe('useSuspenseQuery', () => { return (
- data: {state.data?.pages.join(',')} + data: {state.data.pages.join(',')}
) } @@ -264,6 +264,49 @@ describe('useSuspenseQuery', () => { consoleMock.mockRestore() }) + it('should throw to an ErrorBoundary if select throws an error', async () => { + const consoleMock = vi + .spyOn(console, 'error') + .mockImplementation(() => undefined) + const key = queryKey() + + function Page() { + useSuspenseQuery({ + queryKey: key, + queryFn: async () => { + await sleep(10) + return 'data' + }, + select: () => { + throw new Error('oh on') + }, + }) + + return
rendered
+ } + + const rendered = renderWithClient( + queryClient, + ( +
+
error boundary
+
+ )} + > + + + +
, + ) + + await waitFor(() => rendered.getByText('Loading...')) + + await waitFor(() => rendered.getByText('error boundary')) + + consoleMock.mockRestore() + }) + it('should retry fetch if the reset error boundary has been reset', async () => { const consoleMock = vi .spyOn(console, 'error') diff --git a/packages/react-query/src/errorBoundaryUtils.ts b/packages/react-query/src/errorBoundaryUtils.ts index 7721812058..89a518bdc3 100644 --- a/packages/react-query/src/errorBoundaryUtils.ts +++ b/packages/react-query/src/errorBoundaryUtils.ts @@ -1,6 +1,5 @@ 'use client' import * as React from 'react' -import { shouldThrowError } from './utils' import type { DefaultedQueryObserverOptions, Query, @@ -42,6 +41,18 @@ export const useClearResetErrorBoundary = ( }, [errorResetBoundary]) } +export function shouldThrowError) => boolean>( + throwError: boolean | T | undefined, + params: Parameters, +): boolean { + // Allow throwError function to override throwing behavior on a per-error basis + if (typeof throwError === 'function') { + return throwError(...params) + } + + return !!throwError +} + export const getHasError = < TData, TError, @@ -52,13 +63,18 @@ export const getHasError = < result, errorResetBoundary, throwOnError, + suspense, query, }: { result: QueryObserverResult errorResetBoundary: QueryErrorResetBoundaryValue throwOnError: ThrowOnError + suspense: boolean | undefined query: Query | undefined }) => { + if (suspense && result.data === undefined) { + return true + } return ( result.isError && !errorResetBoundary.isReset() && diff --git a/packages/react-query/src/useBaseQuery.ts b/packages/react-query/src/useBaseQuery.ts index c70230a7b6..5036bef300 100644 --- a/packages/react-query/src/useBaseQuery.ts +++ b/packages/react-query/src/useBaseQuery.ts @@ -112,6 +112,7 @@ export function useBaseQuery< result, errorResetBoundary, throwOnError: defaultedOptions.throwOnError, + suspense: defaultedOptions.suspense, query: client .getQueryCache() .get< diff --git a/packages/react-query/src/useMutation.ts b/packages/react-query/src/useMutation.ts index 34edd450a2..584ee2cf54 100644 --- a/packages/react-query/src/useMutation.ts +++ b/packages/react-query/src/useMutation.ts @@ -1,8 +1,8 @@ 'use client' import * as React from 'react' -import { MutationObserver, notifyManager } from '@tanstack/query-core' +import { MutationObserver, noop, notifyManager } from '@tanstack/query-core' import { useQueryClient } from './QueryClientProvider' -import { noop, shouldThrowError } from './utils' +import { shouldThrowError } from './errorBoundaryUtils' import type { UseMutateFunction, UseMutationOptions, diff --git a/packages/react-query/src/useQueries.ts b/packages/react-query/src/useQueries.ts index 1360426763..228e00fc79 100644 --- a/packages/react-query/src/useQueries.ts +++ b/packages/react-query/src/useQueries.ts @@ -332,6 +332,7 @@ export function useQueries< result, errorResetBoundary, throwOnError: query.throwOnError, + suspense: query.suspense, query: client.getQueryCache().get(query.queryHash), }) ) diff --git a/packages/react-query/src/utils.ts b/packages/react-query/src/utils.ts deleted file mode 100644 index d07a9316fe..0000000000 --- a/packages/react-query/src/utils.ts +++ /dev/null @@ -1,13 +0,0 @@ -export function shouldThrowError) => boolean>( - throwError: boolean | T | undefined, - params: Parameters, -): boolean { - // Allow throwError function to override throwing behavior on a per-error basis - if (typeof throwError === 'function') { - return throwError(...params) - } - - return !!throwError -} - -export function noop() {} diff --git a/packages/solid-query/src/createMutation.ts b/packages/solid-query/src/createMutation.ts index 39c56ff2e3..4080fb8c41 100644 --- a/packages/solid-query/src/createMutation.ts +++ b/packages/solid-query/src/createMutation.ts @@ -1,8 +1,8 @@ -import { MutationObserver } from '@tanstack/query-core' +import { MutationObserver, noop } from '@tanstack/query-core' import { createComputed, createMemo, on, onCleanup } from 'solid-js' import { createStore } from 'solid-js/store' import { useQueryClient } from './QueryClientProvider' -import { noop, shouldThrowError } from './utils' +import { shouldThrowError } from './utils' import type { DefaultError } from '@tanstack/query-core' import type { QueryClient } from './QueryClient' import type { diff --git a/packages/solid-query/src/utils.ts b/packages/solid-query/src/utils.ts index d07a9316fe..b3a928ff6b 100644 --- a/packages/solid-query/src/utils.ts +++ b/packages/solid-query/src/utils.ts @@ -9,5 +9,3 @@ export function shouldThrowError) => boolean>( return !!throwError } - -export function noop() {} diff --git a/packages/svelte-query/src/createMutation.ts b/packages/svelte-query/src/createMutation.ts index 97053fb0f4..d32d3df428 100644 --- a/packages/svelte-query/src/createMutation.ts +++ b/packages/svelte-query/src/createMutation.ts @@ -1,7 +1,7 @@ import { derived, get, readable } from 'svelte/store' -import { MutationObserver, notifyManager } from '@tanstack/query-core' +import { MutationObserver, noop, notifyManager } from '@tanstack/query-core' import { useQueryClient } from './useQueryClient' -import { isSvelteStore, noop } from './utils' +import { isSvelteStore } from './utils' import type { CreateMutateFunction, CreateMutationOptions, diff --git a/packages/svelte-query/src/utils.ts b/packages/svelte-query/src/utils.ts index 617144fae0..eb86225694 100644 --- a/packages/svelte-query/src/utils.ts +++ b/packages/svelte-query/src/utils.ts @@ -6,5 +6,3 @@ export function isSvelteStore( ): obj is Readable { return 'subscribe' in obj && typeof obj.subscribe === 'function' } - -export function noop() {}