From 264b7f68e6a65f5b6b2317536fb525d83b64e316 Mon Sep 17 00:00:00 2001 From: Dominik Dorfmeister Date: Sun, 3 Nov 2024 10:18:22 +0100 Subject: [PATCH] fix(useQuery): don't retryOnMount when prefetchInRender is used otherwise, queries will not stay in error state, but immediately go into pending + fetching again; this is also shown by the fact that an additional test now failed, because it didn't reset the error boundary correctly --- .../src/__tests__/useQuery.promise.test.tsx | 79 +++++++++++++++---- .../react-query/src/errorBoundaryUtils.ts | 6 +- 2 files changed, 68 insertions(+), 17 deletions(-) diff --git a/packages/react-query/src/__tests__/useQuery.promise.test.tsx b/packages/react-query/src/__tests__/useQuery.promise.test.tsx index 1540ae0ce7..b6231dfca7 100644 --- a/packages/react-query/src/__tests__/useQuery.promise.test.tsx +++ b/packages/react-query/src/__tests__/useQuery.promise.test.tsx @@ -2,7 +2,7 @@ import { afterAll, beforeAll, describe, expect, it, vi } from 'vitest' import { fireEvent, waitFor } from '@testing-library/react' import * as React from 'react' import { ErrorBoundary } from 'react-error-boundary' -import { keepPreviousData, useQuery } from '..' +import { QueryErrorResetBoundary, keepPreviousData, useQuery } from '..' import { QueryCache } from '../index' import { createQueryClient, queryKey, renderWithClient, sleep } from './utils' @@ -433,22 +433,27 @@ describe('useQuery().promise', () => { const rendered = renderWithClient( queryClient, - ( - <> - error boundary{' '} - - + + {({ reset }) => ( + ( +
+
error boundary
+ +
+ )} + > + +
)} - > - -
, + , ) await waitFor(() => rendered.getByText('loading..')) @@ -464,6 +469,48 @@ describe('useQuery().promise', () => { expect(queryCount).toBe(2) }) + it('should throw error if the promise fails (colocate suspense and promise)', async () => { + const consoleMock = vi + .spyOn(console, 'error') + .mockImplementation(() => undefined) + + const key = queryKey() + + function MyComponent() { + const query = useQuery({ + queryKey: key, + queryFn: async () => { + await sleep(1) + throw new Error('Error test') + }, + retry: false, + }) + const data = React.use(query.promise) + + return <>{data} + } + + function Page() { + return ( + + + + ) + } + + const rendered = renderWithClient( + queryClient, +
error boundary
}> + +
, + ) + + await waitFor(() => rendered.getByText('loading..')) + await waitFor(() => rendered.getByText('error boundary')) + + consoleMock.mockRestore() + }) + it('should recreate promise with data changes', async () => { const key = queryKey() let suspenseRenderCount = 0 diff --git a/packages/react-query/src/errorBoundaryUtils.ts b/packages/react-query/src/errorBoundaryUtils.ts index 7721812058..3e0d036066 100644 --- a/packages/react-query/src/errorBoundaryUtils.ts +++ b/packages/react-query/src/errorBoundaryUtils.ts @@ -26,7 +26,11 @@ export const ensurePreventErrorBoundaryRetry = < >, errorResetBoundary: QueryErrorResetBoundaryValue, ) => { - if (options.suspense || options.throwOnError) { + if ( + options.suspense || + options.throwOnError || + options.experimental_prefetchInRender + ) { // Prevent retrying failed query if the error boundary has not been reset yet if (!errorResetBoundary.isReset()) { options.retryOnMount = false