Skip to content

Commit e9770b7

Browse files
authored
fix: use hook config on refocus or reconnect (#964)
1 parent 4df81f8 commit e9770b7

File tree

5 files changed

+123
-77
lines changed

5 files changed

+123
-77
lines changed

src/core/query.ts

Lines changed: 13 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -231,33 +231,22 @@ export class Query<TResult, TError> {
231231
)
232232
}
233233

234-
onWindowFocus(): void {
235-
if (
236-
this.observers.some(
237-
observer =>
238-
observer.isStale() &&
239-
observer.config.enabled &&
240-
observer.config.refetchOnWindowFocus
241-
)
242-
) {
243-
this.fetch().catch(noop)
244-
}
245-
246-
this.continue()
247-
}
234+
onInteraction(type: 'focus' | 'online'): void {
235+
// Execute the first observer which is enabled,
236+
// stale and wants to refetch on this interaction.
237+
const observer = this.observers.find(
238+
observer =>
239+
observer.isStale() &&
240+
observer.config.enabled &&
241+
((observer.config.refetchOnWindowFocus && type === 'focus') ||
242+
(observer.config.refetchOnReconnect && type === 'online'))
243+
)
248244

249-
onOnline(): void {
250-
if (
251-
this.observers.some(
252-
observer =>
253-
observer.isStale() &&
254-
observer.config.enabled &&
255-
observer.config.refetchOnReconnect
256-
)
257-
) {
258-
this.fetch().catch(noop)
245+
if (observer) {
246+
observer.fetch().catch(noop)
259247
}
260248

249+
// Continue any paused fetch
261250
this.continue()
262251
}
263252

src/core/queryCache.ts

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -354,15 +354,11 @@ export function makeQueryCache(config?: QueryCacheConfig) {
354354
return new QueryCache(config)
355355
}
356356

357-
export function onVisibilityOrOnlineChange(isOnlineChange: boolean) {
357+
export function onVisibilityOrOnlineChange(type: 'focus' | 'online') {
358358
if (isDocumentVisible() && isOnline()) {
359359
queryCaches.forEach(queryCache => {
360360
queryCache.getQueries().forEach(query => {
361-
if (isOnlineChange) {
362-
query.onOnline()
363-
} else {
364-
query.onWindowFocus()
365-
}
361+
query.onInteraction(type)
366362
})
367363
})
368364
}

src/core/setFocusHandler.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import { createSetHandler, isServer } from './utils'
22
import { onVisibilityOrOnlineChange } from './queryCache'
33

44
export const setFocusHandler = createSetHandler(() =>
5-
onVisibilityOrOnlineChange(false)
5+
onVisibilityOrOnlineChange('focus')
66
)
77

88
setFocusHandler(handleFocus => {

src/core/setOnlineHandler.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import { createSetHandler, isServer } from './utils'
22
import { onVisibilityOrOnlineChange } from './queryCache'
33

44
export const setOnlineHandler = createSetHandler(() =>
5-
onVisibilityOrOnlineChange(true)
5+
onVisibilityOrOnlineChange('online')
66
)
77

88
setOnlineHandler(handleOnline => {

src/react/tests/useQuery.test.tsx

Lines changed: 106 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -644,7 +644,7 @@ describe('useQuery', () => {
644644

645645
await queryCache.prefetchQuery(key, () => 'prefetch')
646646

647-
await sleep(40)
647+
await sleep(20)
648648

649649
function FirstComponent() {
650650
const state = useQuery(key, () => 'one', {
@@ -656,7 +656,7 @@ describe('useQuery', () => {
656656

657657
function SecondComponent() {
658658
const state = useQuery(key, () => 'two', {
659-
staleTime: 20,
659+
staleTime: 10,
660660
})
661661
states2.push(state)
662662
return null
@@ -673,50 +673,55 @@ describe('useQuery', () => {
673673

674674
render(<Page />)
675675

676-
await waitFor(() => expect(states1.length).toBe(4))
677-
await waitFor(() => expect(states2.length).toBe(4))
678-
679-
// First render
680-
expect(states1[0]).toMatchObject({
681-
data: 'prefetch',
682-
isStale: false,
683-
})
684-
// Second useQuery started fetching
685-
expect(states1[1]).toMatchObject({
686-
data: 'prefetch',
687-
isStale: false,
688-
})
689-
// Second useQuery data came in
690-
expect(states1[2]).toMatchObject({
691-
data: 'two',
692-
isStale: false,
693-
})
694-
// Data became stale after 100ms
695-
expect(states1[3]).toMatchObject({
696-
data: 'two',
697-
isStale: true,
698-
})
676+
await waitFor(() =>
677+
expect(states1).toMatchObject([
678+
// First render
679+
{
680+
data: 'prefetch',
681+
isStale: false,
682+
},
683+
// Second useQuery started fetching
684+
{
685+
data: 'prefetch',
686+
isStale: false,
687+
},
688+
// Second useQuery data came in
689+
{
690+
data: 'two',
691+
isStale: false,
692+
},
693+
// Data became stale after 100ms
694+
{
695+
data: 'two',
696+
isStale: true,
697+
},
698+
])
699+
)
699700

700-
// First render, data is stale
701-
expect(states2[0]).toMatchObject({
702-
data: 'prefetch',
703-
isStale: true,
704-
})
705-
// Second useQuery started fetching
706-
expect(states2[1]).toMatchObject({
707-
data: 'prefetch',
708-
isStale: true,
709-
})
710-
// Second useQuery data came in
711-
expect(states2[2]).toMatchObject({
712-
data: 'two',
713-
isStale: false,
714-
})
715-
// Data became stale after 5ms
716-
expect(states2[3]).toMatchObject({
717-
data: 'two',
718-
isStale: true,
719-
})
701+
await waitFor(() =>
702+
expect(states2).toMatchObject([
703+
// First render, data is stale
704+
{
705+
data: 'prefetch',
706+
isStale: true,
707+
},
708+
// Second useQuery started fetching
709+
{
710+
data: 'prefetch',
711+
isStale: true,
712+
},
713+
// Second useQuery data came in
714+
{
715+
data: 'two',
716+
isStale: false,
717+
},
718+
// Data became stale after 5ms
719+
{
720+
data: 'two',
721+
isStale: true,
722+
},
723+
])
724+
)
720725
})
721726

722727
it('should re-render when a query becomes stale', async () => {
@@ -1220,6 +1225,62 @@ describe('useQuery', () => {
12201225
consoleMock.mockRestore()
12211226
})
12221227

1228+
it('should refetch after focus regain', async () => {
1229+
const key = queryKey()
1230+
const states: QueryResult<string>[] = []
1231+
const consoleMock = mockConsoleError()
1232+
1233+
// make page unfocused
1234+
const originalVisibilityState = document.visibilityState
1235+
mockVisibilityState('hidden')
1236+
1237+
// set data in cache to check if the hook query fn is actually called
1238+
queryCache.setQueryData(key, 'prefetched')
1239+
1240+
function Page() {
1241+
const state = useQuery(key, () => 'data')
1242+
states.push(state)
1243+
return null
1244+
}
1245+
1246+
render(<Page />)
1247+
1248+
await waitFor(() => expect(states.length).toBe(2))
1249+
1250+
act(() => {
1251+
// reset visibilityState to original value
1252+
mockVisibilityState(originalVisibilityState)
1253+
window.dispatchEvent(new FocusEvent('focus'))
1254+
})
1255+
1256+
await waitFor(() => expect(states.length).toBe(4))
1257+
1258+
expect(states).toMatchObject([
1259+
{
1260+
data: 'prefetched',
1261+
isFetching: false,
1262+
isStale: false,
1263+
},
1264+
{
1265+
data: 'prefetched',
1266+
isFetching: false,
1267+
isStale: true,
1268+
},
1269+
{
1270+
data: 'prefetched',
1271+
isFetching: true,
1272+
isStale: true,
1273+
},
1274+
{
1275+
data: 'data',
1276+
isFetching: false,
1277+
isStale: true,
1278+
},
1279+
])
1280+
1281+
consoleMock.mockRestore()
1282+
})
1283+
12231284
// See https://github.com/tannerlinsley/react-query/issues/195
12241285
it('should refetch if stale after a prefetch', async () => {
12251286
const key = queryKey()

0 commit comments

Comments
 (0)