Skip to content

Commit

Permalink
fix: use hook config on refocus or reconnect (#964)
Browse files Browse the repository at this point in the history
  • Loading branch information
boschni committed Sep 4, 2020
1 parent 4df81f8 commit e9770b7
Show file tree
Hide file tree
Showing 5 changed files with 123 additions and 77 deletions.
37 changes: 13 additions & 24 deletions src/core/query.ts
Original file line number Diff line number Diff line change
Expand Up @@ -231,33 +231,22 @@ export class Query<TResult, TError> {
)
}

onWindowFocus(): void {
if (
this.observers.some(
observer =>
observer.isStale() &&
observer.config.enabled &&
observer.config.refetchOnWindowFocus
)
) {
this.fetch().catch(noop)
}

this.continue()
}
onInteraction(type: 'focus' | 'online'): void {
// Execute the first observer which is enabled,
// stale and wants to refetch on this interaction.
const observer = this.observers.find(
observer =>
observer.isStale() &&
observer.config.enabled &&
((observer.config.refetchOnWindowFocus && type === 'focus') ||
(observer.config.refetchOnReconnect && type === 'online'))
)

onOnline(): void {
if (
this.observers.some(
observer =>
observer.isStale() &&
observer.config.enabled &&
observer.config.refetchOnReconnect
)
) {
this.fetch().catch(noop)
if (observer) {
observer.fetch().catch(noop)
}

// Continue any paused fetch
this.continue()
}

Expand Down
8 changes: 2 additions & 6 deletions src/core/queryCache.ts
Original file line number Diff line number Diff line change
Expand Up @@ -354,15 +354,11 @@ export function makeQueryCache(config?: QueryCacheConfig) {
return new QueryCache(config)
}

export function onVisibilityOrOnlineChange(isOnlineChange: boolean) {
export function onVisibilityOrOnlineChange(type: 'focus' | 'online') {
if (isDocumentVisible() && isOnline()) {
queryCaches.forEach(queryCache => {
queryCache.getQueries().forEach(query => {
if (isOnlineChange) {
query.onOnline()
} else {
query.onWindowFocus()
}
query.onInteraction(type)
})
})
}
Expand Down
2 changes: 1 addition & 1 deletion src/core/setFocusHandler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { createSetHandler, isServer } from './utils'
import { onVisibilityOrOnlineChange } from './queryCache'

export const setFocusHandler = createSetHandler(() =>
onVisibilityOrOnlineChange(false)
onVisibilityOrOnlineChange('focus')
)

setFocusHandler(handleFocus => {
Expand Down
2 changes: 1 addition & 1 deletion src/core/setOnlineHandler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { createSetHandler, isServer } from './utils'
import { onVisibilityOrOnlineChange } from './queryCache'

export const setOnlineHandler = createSetHandler(() =>
onVisibilityOrOnlineChange(true)
onVisibilityOrOnlineChange('online')
)

setOnlineHandler(handleOnline => {
Expand Down
151 changes: 106 additions & 45 deletions src/react/tests/useQuery.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -644,7 +644,7 @@ describe('useQuery', () => {

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

await sleep(40)
await sleep(20)

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

function SecondComponent() {
const state = useQuery(key, () => 'two', {
staleTime: 20,
staleTime: 10,
})
states2.push(state)
return null
Expand All @@ -673,50 +673,55 @@ describe('useQuery', () => {

render(<Page />)

await waitFor(() => expect(states1.length).toBe(4))
await waitFor(() => expect(states2.length).toBe(4))

// First render
expect(states1[0]).toMatchObject({
data: 'prefetch',
isStale: false,
})
// Second useQuery started fetching
expect(states1[1]).toMatchObject({
data: 'prefetch',
isStale: false,
})
// Second useQuery data came in
expect(states1[2]).toMatchObject({
data: 'two',
isStale: false,
})
// Data became stale after 100ms
expect(states1[3]).toMatchObject({
data: 'two',
isStale: true,
})
await waitFor(() =>
expect(states1).toMatchObject([
// First render
{
data: 'prefetch',
isStale: false,
},
// Second useQuery started fetching
{
data: 'prefetch',
isStale: false,
},
// Second useQuery data came in
{
data: 'two',
isStale: false,
},
// Data became stale after 100ms
{
data: 'two',
isStale: true,
},
])
)

// First render, data is stale
expect(states2[0]).toMatchObject({
data: 'prefetch',
isStale: true,
})
// Second useQuery started fetching
expect(states2[1]).toMatchObject({
data: 'prefetch',
isStale: true,
})
// Second useQuery data came in
expect(states2[2]).toMatchObject({
data: 'two',
isStale: false,
})
// Data became stale after 5ms
expect(states2[3]).toMatchObject({
data: 'two',
isStale: true,
})
await waitFor(() =>
expect(states2).toMatchObject([
// First render, data is stale
{
data: 'prefetch',
isStale: true,
},
// Second useQuery started fetching
{
data: 'prefetch',
isStale: true,
},
// Second useQuery data came in
{
data: 'two',
isStale: false,
},
// Data became stale after 5ms
{
data: 'two',
isStale: true,
},
])
)
})

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

it('should refetch after focus regain', async () => {
const key = queryKey()
const states: QueryResult<string>[] = []
const consoleMock = mockConsoleError()

// make page unfocused
const originalVisibilityState = document.visibilityState
mockVisibilityState('hidden')

// set data in cache to check if the hook query fn is actually called
queryCache.setQueryData(key, 'prefetched')

function Page() {
const state = useQuery(key, () => 'data')
states.push(state)
return null
}

render(<Page />)

await waitFor(() => expect(states.length).toBe(2))

act(() => {
// reset visibilityState to original value
mockVisibilityState(originalVisibilityState)
window.dispatchEvent(new FocusEvent('focus'))
})

await waitFor(() => expect(states.length).toBe(4))

expect(states).toMatchObject([
{
data: 'prefetched',
isFetching: false,
isStale: false,
},
{
data: 'prefetched',
isFetching: false,
isStale: true,
},
{
data: 'prefetched',
isFetching: true,
isStale: true,
},
{
data: 'data',
isFetching: false,
isStale: true,
},
])

consoleMock.mockRestore()
})

// See https://github.com/tannerlinsley/react-query/issues/195
it('should refetch if stale after a prefetch', async () => {
const key = queryKey()
Expand Down

1 comment on commit e9770b7

@vercel
Copy link

@vercel vercel bot commented on e9770b7 Sep 4, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.