Skip to content

Commit

Permalink
fix(scheduleGarbageCollection): Do not garbage collect newly cached q…
Browse files Browse the repository at this point in the history
…ueries of the same hash (#332)

* Add manual/prefetch cleanup test that fails

* Prefetch both queries in second test

* Add cleanup comment that will make the tests pass

* Store when the GC was initiated and compare against updatedAt

* Replace solution with state marker check and streamline test

* Undo setting.json change

* Undo setting.json change
  • Loading branch information
kamranayub committed Apr 8, 2020
1 parent 63f3d82 commit 67755ce
Show file tree
Hide file tree
Showing 3 changed files with 42 additions and 3 deletions.
13 changes: 12 additions & 1 deletion src/queryCache.js
Expand Up @@ -17,6 +17,7 @@ export const queryCache = makeQueryCache()
const actionInit = {}
const actionFailed = {}
const actionMarkStale = {}
const actionMarkGC = {}
const actionFetch = {}
const actionSuccess = {}
const actionError = {}
Expand Down Expand Up @@ -238,9 +239,12 @@ export function makeQueryCache() {
}

query.scheduleGarbageCollection = () => {
dispatch({ type: actionMarkGC })
query.cacheTimeout = setTimeout(
() => {
cache.removeQueries(d => d.queryHash === query.queryHash)
cache.removeQueries(
d => d.state.markedForGarbageCollection && d.queryHash === query.queryHash
)
},
typeof query.state.data === 'undefined' &&
query.state.status !== 'error'
Expand Down Expand Up @@ -447,6 +451,7 @@ export function defaultQueryReducer(state, action) {
canFetchMore: false,
failureCount: 0,
isStale: action.isStale,
markedForGarbageCollection: false,
data: action.initialData,
updatedAt: action.hasInitialData ? Date.now() : 0,
}
Expand All @@ -460,6 +465,12 @@ export function defaultQueryReducer(state, action) {
...state,
isStale: true,
}
case actionMarkGC: {
return {
...state,
markedForGarbageCollection: true,
}
}
case actionFetch:
return {
...state,
Expand Down
30 changes: 30 additions & 0 deletions src/tests/queryCache.test.js
Expand Up @@ -143,4 +143,34 @@ describe('queryCache', () => {
await sleep(50)
expect(query.state.isStale).toBe(false)
})

test('query is garbage collected when unsubscribed to', async () => {
const queryKey = 'key'
const fetchData = () => Promise.resolve('data')
await queryCache.prefetchQuery(queryKey, fetchData, { cacheTime: 0 })
const query = queryCache.getQuery(queryKey)
expect(query.state.markedForGarbageCollection).toBe(false)
const unsubscribe = query.subscribe(1)
unsubscribe()
expect(query.state.markedForGarbageCollection).toBe(true)
await sleep(1)
expect(queryCache.getQuery(queryKey)).toBeUndefined()
})

test('query is not garbage collected unless markedForGarbageCollection is true', async () => {
const queryKey = 'key'
const fetchData = () => Promise.resolve(undefined)
await queryCache.prefetchQuery(queryKey, fetchData, { cacheTime: 0 })
const query = queryCache.getQuery(queryKey)
expect(query.state.markedForGarbageCollection).toBe(false)
const unsubscribe = query.subscribe(1)
unsubscribe()
expect(query.state.markedForGarbageCollection).toBe(true)
queryCache.clear()
queryCache.setQueryData(queryKey, 'data')
await sleep(1)
const newQuery = queryCache.getQuery(queryKey)
expect(newQuery.state.markedForGarbageCollection).toBe(false)
expect(newQuery.state.data).toBe('data')
})
})
2 changes: 0 additions & 2 deletions src/tests/useQuery.test.js
Expand Up @@ -3,7 +3,6 @@ import {
act,
waitForElement,
fireEvent,
cleanup,
} from '@testing-library/react'
import * as React from 'react'

Expand All @@ -13,7 +12,6 @@ import { sleep } from './utils'
describe('useQuery', () => {
afterEach(() => {
queryCache.clear()
cleanup()
})

// See https://github.com/tannerlinsley/react-query/issues/105
Expand Down

0 comments on commit 67755ce

Please sign in to comment.