Skip to content

Commit a29f1a6

Browse files
authored
fix(hydration): do not alter fetchStatus when hydrating existing queries (#6088)
1 parent b29824a commit a29f1a6

File tree

2 files changed

+47
-14
lines changed

2 files changed

+47
-14
lines changed

packages/query-core/src/hydration.ts

Lines changed: 14 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -139,19 +139,15 @@ export function hydrate(
139139
)
140140
})
141141

142-
queries.forEach((dehydratedQuery) => {
143-
const query = queryCache.get(dehydratedQuery.queryHash)
144-
145-
// Reset fetch status to idle in the dehydrated state to avoid
146-
// query being stuck in fetching state upon hydration
147-
const dehydratedQueryState = {
148-
...dehydratedQuery.state,
149-
fetchStatus: 'idle' as const,
150-
}
142+
queries.forEach(({ queryKey, state, queryHash }) => {
143+
const query = queryCache.get(queryHash)
151144

152145
// Do not hydrate if an existing query exists with newer data
153146
if (query) {
154-
if (query.state.dataUpdatedAt < dehydratedQueryState.dataUpdatedAt) {
147+
if (query.state.dataUpdatedAt < state.dataUpdatedAt) {
148+
// omit fetchStatus from dehydrated state
149+
// so that query stays in its current fetchStatus
150+
const { fetchStatus: _ignored, ...dehydratedQueryState } = state
155151
query.setState(dehydratedQueryState)
156152
}
157153
return
@@ -162,10 +158,15 @@ export function hydrate(
162158
client,
163159
{
164160
...options?.defaultOptions?.queries,
165-
queryKey: dehydratedQuery.queryKey,
166-
queryHash: dehydratedQuery.queryHash,
161+
queryKey,
162+
queryHash,
163+
},
164+
// Reset fetch status to idle to avoid
165+
// query being stuck in fetching state upon hydration
166+
{
167+
...state,
168+
fetchStatus: 'idle',
167169
},
168-
dehydratedQueryState,
169170
)
170171
})
171172
}

packages/query-core/src/tests/hydration.test.tsx

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -427,7 +427,7 @@ describe('dehydration and rehydration', () => {
427427
queryClient.clear()
428428
})
429429

430-
test('should set the fetchStatus to idle in all cases when dehydrating', async () => {
430+
test('should set the fetchStatus to idle when creating a query with dehydrate', async () => {
431431
const queryCache = new QueryCache()
432432
const queryClient = createQueryClient({ queryCache })
433433

@@ -466,4 +466,36 @@ describe('dehydration and rehydration', () => {
466466
hydrate(hydrationClient, parsed)
467467
expect(hydrationCache.find(['string'])?.state.fetchStatus).toBe('idle')
468468
})
469+
470+
test('should not change fetchStatus when updating a query with dehydrate', async () => {
471+
const queryClient = createQueryClient()
472+
473+
const options = {
474+
queryKey: ['string'],
475+
queryFn: async () => {
476+
await sleep(10)
477+
return 'string'
478+
},
479+
} as const
480+
481+
await queryClient.prefetchQuery(options)
482+
483+
const dehydrated = dehydrate(queryClient)
484+
expect(
485+
dehydrated.queries.find((q) => q.queryHash === '["string"]')?.state
486+
.fetchStatus,
487+
).toBe('idle')
488+
const stringified = JSON.stringify(dehydrated)
489+
490+
// ---
491+
const parsed = JSON.parse(stringified)
492+
const hydrationCache = new QueryCache()
493+
const hydrationClient = createQueryClient({ queryCache: hydrationCache })
494+
495+
const promise = hydrationClient.prefetchQuery(options)
496+
hydrate(hydrationClient, parsed)
497+
expect(hydrationCache.find(['string'])?.state.fetchStatus).toBe('fetching')
498+
await promise
499+
expect(hydrationCache.find(['string'])?.state.fetchStatus).toBe('idle')
500+
})
469501
})

0 commit comments

Comments
 (0)