Skip to content

Commit e42ddfe

Browse files
authored
fix(core): observing "promise" needs to implicitly observe "data" (#9772)
* fix(core): using the promise means we have to observer data * test * chore: fix other tests
1 parent 64507ba commit e42ddfe

File tree

3 files changed

+74
-22
lines changed

3 files changed

+74
-22
lines changed

.changeset/good-windows-tell.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@tanstack/query-core': patch
3+
---
4+
5+
fix: observing "promise" needs to implicitly observe "data"

packages/query-core/src/queryObserver.ts

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -269,16 +269,18 @@ export class QueryObserver<
269269
get: (target, key) => {
270270
this.trackProp(key as keyof QueryObserverResult)
271271
onPropTracked?.(key as keyof QueryObserverResult)
272-
if (
273-
key === 'promise' &&
274-
!this.options.experimental_prefetchInRender &&
275-
this.#currentThenable.status === 'pending'
276-
) {
277-
this.#currentThenable.reject(
278-
new Error(
279-
'experimental_prefetchInRender feature flag is not enabled',
280-
),
281-
)
272+
if (key === 'promise') {
273+
this.trackProp('data')
274+
if (
275+
!this.options.experimental_prefetchInRender &&
276+
this.#currentThenable.status === 'pending'
277+
) {
278+
this.#currentThenable.reject(
279+
new Error(
280+
'experimental_prefetchInRender feature flag is not enabled',
281+
),
282+
)
283+
}
282284
}
283285
return Reflect.get(target, key)
284286
},

packages/react-query/src/__tests__/useQuery.promise.test.tsx

Lines changed: 57 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,13 @@ import {
66
useTrackRenders,
77
} from '@testing-library/react-render-stream'
88
import { queryKey } from '@tanstack/query-test-utils'
9+
import { waitFor } from '@testing-library/react'
910
import {
1011
QueryClient,
1112
QueryClientProvider,
1213
QueryErrorResetBoundary,
1314
keepPreviousData,
15+
useInfiniteQuery,
1416
useQuery,
1517
} from '..'
1618
import { QueryCache } from '../index'
@@ -417,7 +419,7 @@ describe('useQuery().promise', () => {
417419
{
418420
const { renderedComponents, withinDOM } = await renderStream.takeRender()
419421
withinDOM().getByText('test-0')
420-
expect(renderedComponents).toEqual([MyComponent])
422+
expect(renderedComponents).toEqual([Page, MyComponent])
421423
}
422424

423425
rendered.getByRole('button', { name: 'increment' }).click()
@@ -485,7 +487,7 @@ describe('useQuery().promise', () => {
485487
{
486488
const { renderedComponents, withinDOM } = await renderStream.takeRender()
487489
withinDOM().getByText('test')
488-
expect(renderedComponents).toEqual([MyComponent])
490+
expect(renderedComponents).toEqual([Page, MyComponent])
489491
}
490492
})
491493

@@ -679,7 +681,7 @@ describe('useQuery().promise', () => {
679681
{
680682
const { renderedComponents, withinDOM } = await renderStream.takeRender()
681683
withinDOM().getByText('test1')
682-
expect(renderedComponents).toEqual([MyComponent])
684+
expect(renderedComponents).toEqual([Page, MyComponent])
683685
}
684686

685687
queryClient.setQueryData(key, 'test2')
@@ -1094,7 +1096,7 @@ describe('useQuery().promise', () => {
10941096
{
10951097
const { renderedComponents, withinDOM } = await renderStream.takeRender()
10961098
withinDOM().getByText('test0')
1097-
expect(renderedComponents).toEqual([MyComponent])
1099+
expect(renderedComponents).toEqual([Page, MyComponent])
10981100
}
10991101

11001102
rendered.getByText('inc').click()
@@ -1108,7 +1110,7 @@ describe('useQuery().promise', () => {
11081110
{
11091111
const { renderedComponents, withinDOM } = await renderStream.takeRender()
11101112
withinDOM().getByText('test1')
1111-
expect(renderedComponents).toEqual([MyComponent])
1113+
expect(renderedComponents).toEqual([Page, MyComponent])
11121114
}
11131115

11141116
rendered.getByText('dec').click()
@@ -1282,13 +1284,13 @@ describe('useQuery().promise', () => {
12821284
rendered.getByText('dec').click()
12831285
{
12841286
const { snapshot } = await renderStream.takeRender()
1285-
expect(snapshot).toMatchObject({ data: 'test2' })
1287+
expect(snapshot).toMatchObject({ data: 'test3' })
12861288
}
12871289

12881290
rendered.getByText('dec').click()
12891291
{
12901292
const { snapshot } = await renderStream.takeRender()
1291-
expect(snapshot).toMatchObject({ data: 'test1' })
1293+
expect(snapshot).toMatchObject({ data: 'test3' })
12921294
}
12931295

12941296
rendered.getByText('dec').click()
@@ -1297,11 +1299,7 @@ describe('useQuery().promise', () => {
12971299
expect(snapshot).toMatchObject({ data: 'test0' })
12981300
}
12991301

1300-
{
1301-
const { snapshot, withinDOM } = await renderStream.takeRender()
1302-
withinDOM().getByText('test0new')
1303-
expect(snapshot).toMatchObject({ data: 'test0new' })
1304-
}
1302+
await waitFor(() => rendered.getByText('test0new'))
13051303
})
13061304

13071305
it('should not suspend indefinitely with multiple, nested observers)', async () => {
@@ -1383,4 +1381,51 @@ describe('useQuery().promise', () => {
13831381
.observers.length,
13841382
).toBe(2)
13851383
})
1384+
1385+
it('should implicitly observe data when promise is used', async () => {
1386+
const key = queryKey()
1387+
1388+
const renderStream = createRenderStream({ snapshotDOM: true })
1389+
1390+
function Page() {
1391+
useTrackRenders()
1392+
const query = useInfiniteQuery({
1393+
queryKey: key,
1394+
queryFn: async () => {
1395+
await vi.advanceTimersByTimeAsync(1)
1396+
return { nextCursor: 1, data: 'test' }
1397+
},
1398+
initialPageParam: 0,
1399+
getNextPageParam: (lastPage) => lastPage.nextCursor,
1400+
})
1401+
1402+
React.use(query.promise)
1403+
1404+
const hasNextPage = query.hasNextPage
1405+
1406+
return (
1407+
<div>
1408+
<div>hasNextPage: {String(hasNextPage)}</div>
1409+
</div>
1410+
)
1411+
}
1412+
1413+
await renderStream.render(
1414+
<QueryClientProvider client={queryClient}>
1415+
<React.Suspense fallback="loading..">
1416+
<Page />
1417+
</React.Suspense>
1418+
</QueryClientProvider>,
1419+
)
1420+
1421+
{
1422+
const { withinDOM } = await renderStream.takeRender()
1423+
expect(withinDOM().getByText('loading..')).toBeInTheDocument()
1424+
}
1425+
1426+
{
1427+
const { withinDOM } = await renderStream.takeRender()
1428+
expect(withinDOM().getByText('hasNextPage: true')).toBeInTheDocument()
1429+
}
1430+
})
13861431
})

0 commit comments

Comments
 (0)