Skip to content

Commit

Permalink
fix(useQuery): don't retryOnMount when prefetchInRender is used (#8247)
Browse files Browse the repository at this point in the history
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
  • Loading branch information
TkDodo authored Nov 3, 2024
1 parent fdc5c8e commit 74f0d6a
Show file tree
Hide file tree
Showing 2 changed files with 68 additions and 17 deletions.
79 changes: 63 additions & 16 deletions packages/react-query/src/__tests__/useQuery.promise.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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'

Expand Down Expand Up @@ -433,22 +433,27 @@ describe('useQuery().promise', () => {

const rendered = renderWithClient(
queryClient,
<ErrorBoundary
fallbackRender={(props) => (
<>
error boundary{' '}
<button
onClick={() => {
props.resetErrorBoundary()
}}
>
resetErrorBoundary
</button>
</>
<QueryErrorResetBoundary>
{({ reset }) => (
<ErrorBoundary
onReset={reset}
fallbackRender={({ resetErrorBoundary }) => (
<div>
<div>error boundary</div>
<button
onClick={() => {
resetErrorBoundary()
}}
>
resetErrorBoundary
</button>
</div>
)}
>
<Page />
</ErrorBoundary>
)}
>
<Page />
</ErrorBoundary>,
</QueryErrorResetBoundary>,
)

await waitFor(() => rendered.getByText('loading..'))
Expand All @@ -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 (
<React.Suspense fallback="loading..">
<MyComponent />
</React.Suspense>
)
}

const rendered = renderWithClient(
queryClient,
<ErrorBoundary fallbackRender={() => <div>error boundary</div>}>
<Page />
</ErrorBoundary>,
)

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
Expand Down
6 changes: 5 additions & 1 deletion packages/react-query/src/errorBoundaryUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down

0 comments on commit 74f0d6a

Please sign in to comment.