Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(react): don't set options before suspending #6611

Merged
merged 4 commits into from
Dec 29, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions packages/query-core/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -345,7 +345,7 @@ export type DefaultedQueryObserverOptions<
TQueryKey extends QueryKey = QueryKey,
> = WithRequired<
QueryObserverOptions<TQueryFnData, TError, TData, TQueryData, TQueryKey>,
'throwOnError' | 'refetchOnReconnect'
'throwOnError' | 'refetchOnReconnect' | 'queryHash'
>

export interface InfiniteQueryObserverOptions<
Expand Down Expand Up @@ -381,7 +381,7 @@ export type DefaultedInfiniteQueryObserverOptions<
TQueryKey,
TPageParam
>,
'throwOnError' | 'refetchOnReconnect'
'throwOnError' | 'refetchOnReconnect' | 'queryHash'
>

export interface FetchQueryOptions<
Expand Down
57 changes: 57 additions & 0 deletions packages/react-query/src/__tests__/suspense.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -1033,4 +1033,61 @@ describe('useSuspenseQueries', () => {

await waitFor(() => rendered.getByText('data1'))
})

it('should not request old data inside transitions (issue #6486)', async () => {
const key = queryKey()
let queryFnCount = 0

function App() {
const [count, setCount] = React.useState(0)

return (
<div>
<button
onClick={() => React.startTransition(() => setCount(count + 1))}
>
inc
</button>
<React.Suspense fallback={'Loading...'}>
<Page count={count} />
</React.Suspense>
</div>
)
}

function Page({ count }: { count: number }) {
const { data } = useSuspenseQuery({
queryKey: [key, count],
queryFn: async () => {
queryFnCount++
await sleep(10)
return 'data' + count
},
})

return (
<div>
<div>{String(data)}</div>
</div>
)
}

const rendered = renderWithClient(
queryClient,

<App />,
)

await waitFor(() => rendered.getByText('Loading...'))

await waitFor(() => rendered.getByText('data0'))

fireEvent.click(rendered.getByText('inc'))

await waitFor(() => rendered.getByText('data1'))

await sleep(20)

expect(queryFnCount).toBe(2)
})
})
3 changes: 2 additions & 1 deletion packages/react-query/src/errorBoundaryUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -57,12 +57,13 @@ export const getHasError = <
result: QueryObserverResult<TData, TError>
errorResetBoundary: QueryErrorResetBoundaryValue
throwOnError: ThrowOnError<TQueryFnData, TError, TQueryData, TQueryKey>
query: Query<TQueryFnData, TError, TQueryData, TQueryKey>
query: Query<TQueryFnData, TError, TQueryData, TQueryKey> | undefined
}) => {
return (
result.isError &&
!errorResetBoundary.isReset() &&
!result.isFetching &&
query &&
shouldThrowError(throwOnError, [result.error, query])
)
}
10 changes: 8 additions & 2 deletions packages/react-query/src/useBaseQuery.ts
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,6 @@ export function useBaseQuery<
// Do the same thing as the effect right above because the effect won't run
// when we suspend but also, the component won't re-mount so our observer would
// be out of date.
observer.setOptions(defaultedOptions, { listeners: false })
throw fetchOptimistic(defaultedOptions, observer, errorResetBoundary)
}

Expand All @@ -104,7 +103,14 @@ export function useBaseQuery<
result,
errorResetBoundary,
throwOnError: defaultedOptions.throwOnError,
query: observer.getCurrentQuery(),
query: client
.getQueryCache()
.get<
TQueryFnData,
TError,
TQueryData,
TQueryKey
>(defaultedOptions.queryHash),
})
) {
throw result.error
Expand Down
27 changes: 12 additions & 15 deletions packages/react-query/src/useQueries.ts
Original file line number Diff line number Diff line change
Expand Up @@ -329,24 +329,21 @@ export function useQueries<
: []

if (suspensePromises.length > 0) {
observer.setQueries(
defaultedQueries,
options as QueriesObserverOptions<TCombinedResult>,
{
listeners: false,
},
)
throw Promise.all(suspensePromises)
}
const observerQueries = observer.getQueries()
const firstSingleResultWhichShouldThrow = optimisticResult.find(
(result, index) =>
getHasError({
result,
errorResetBoundary,
throwOnError: defaultedQueries[index]?.throwOnError ?? false,
query: observerQueries[index]!,
}),
(result, index) => {
const query = defaultedQueries[index]
return (
query &&
getHasError({
result,
errorResetBoundary,
throwOnError: query.throwOnError,
query: client.getQueryCache().get(query.queryHash),
})
)
},
)

if (firstSingleResultWhichShouldThrow?.error) {
Expand Down