Skip to content

Commit b5686c2

Browse files
committed
fix(core): change shouldFetchOptionally condition
Change this condition to not change the status of result to 'loading' when state.status is 'error' Fixes #2187
1 parent 6bbb371 commit b5686c2

File tree

2 files changed

+71
-0
lines changed

2 files changed

+71
-0
lines changed

src/core/queryObserver.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -763,6 +763,7 @@ function shouldFetchOptionally(
763763
return (
764764
options.enabled !== false &&
765765
(query !== prevQuery || prevOptions.enabled === false) &&
766+
query.state.status !== 'error' &&
766767
isStale(query, options)
767768
)
768769
}

src/react/tests/suspense.test.tsx

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -577,4 +577,74 @@ describe("useQuery's in Suspense mode", () => {
577577
expect(queryFn).toHaveBeenCalledTimes(1)
578578
await waitFor(() => rendered.getByLabelText('fire'))
579579
})
580+
581+
it('should error catched in error boundary without infinite loop', async () => {
582+
const key = queryKey()
583+
584+
const consoleMock = mockConsoleError()
585+
586+
let succeed = true
587+
588+
function Page() {
589+
const [nonce] = React.useState(0)
590+
const queryKeys = `${key}-${succeed}`
591+
const result = useQuery(
592+
queryKeys,
593+
async () => {
594+
await sleep(100)
595+
if (!succeed) {
596+
throw new Error('Suspense Error Bingo')
597+
} else {
598+
return nonce
599+
}
600+
},
601+
{
602+
retry: false,
603+
suspense: true,
604+
}
605+
)
606+
return (
607+
<div>
608+
<span>rendered</span> <span>{result.data}</span>
609+
<button
610+
aria-label="fail"
611+
onClick={async () => {
612+
await queryClient.resetQueries()
613+
}}
614+
>
615+
fail
616+
</button>
617+
</div>
618+
)
619+
}
620+
621+
function App() {
622+
const { reset } = useQueryErrorResetBoundary()
623+
return (
624+
<ErrorBoundary
625+
onReset={reset}
626+
fallbackRender={() => <div>error boundary</div>}
627+
>
628+
<React.Suspense fallback="Loading...">
629+
<Page />
630+
</React.Suspense>
631+
</ErrorBoundary>
632+
)
633+
}
634+
635+
const rendered = renderWithClient(queryClient, <App />)
636+
637+
// render suspense fallback (Loading...)
638+
await waitFor(() => rendered.getByText('Loading...'))
639+
// resolve promise -> render Page (rendered)
640+
await waitFor(() => rendered.getByText('rendered'))
641+
642+
// change query key
643+
succeed = false
644+
// reset query -> and throw error
645+
fireEvent.click(rendered.getByLabelText('fail'))
646+
// render error boundary fallback (error boundary)
647+
await waitFor(() => rendered.getByText('error boundary'), { timeout: 500 })
648+
consoleMock.mockRestore()
649+
})
580650
})

0 commit comments

Comments
 (0)