Skip to content

Commit 21d942b

Browse files
author
Kamran Ayub
authored
fix(QueryCache): Use default configuration used for QueryCache instance for context (TanStack#808)
* Add failing test * useConfigContext should use queryCache configRef, which will be defaultConfigRef by default * ci * Add failing test * useConfigContext should use queryCache configRef, which will be defaultConfigRef by default * use accessor * Update for TS * Add failing test for associated queries * Add failing test for notifyGlobalListeners * rename to defaultQueryCache in module scope to catch name conflicts * Fix passing incorrect queryCache ref
1 parent 46a5584 commit 21d942b

File tree

4 files changed

+162
-74
lines changed

4 files changed

+162
-74
lines changed

src/core/queryCache.ts

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -115,7 +115,11 @@ export class QueryCache {
115115
0
116116
)
117117

118-
this.globalListeners.forEach(d => d(queryCache, query))
118+
this.globalListeners.forEach(d => d(this, query))
119+
}
120+
121+
getDefaultConfig() {
122+
return this.configRef.current
119123
}
120124

121125
subscribe(listener: QueryCacheListener): () => void {
@@ -242,7 +246,7 @@ export class QueryCache {
242246

243247
if (!query) {
244248
query = new Query<TResult, TError>({
245-
queryCache,
249+
queryCache: this,
246250
queryKey,
247251
queryHash,
248252
config,
@@ -403,9 +407,9 @@ export class QueryCache {
403407
}
404408
}
405409

406-
export const queryCache = makeQueryCache({ frozen: isServer })
407-
408-
export const queryCaches = [queryCache]
410+
const defaultQueryCache = makeQueryCache({ frozen: isServer })
411+
export { defaultQueryCache as queryCache }
412+
export const queryCaches = [defaultQueryCache]
409413

410414
export function makeQueryCache(config?: QueryCacheConfig) {
411415
return new QueryCache(config)

src/core/tests/queryCache.test.tsx

Lines changed: 111 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { sleep } from './utils'
2-
import { queryCache, queryCaches } from '../'
2+
import { queryCache as defaultQueryCache, queryCaches } from '../'
33
import { makeQueryCache } from '../queryCache'
44

55
describe('queryCache', () => {
@@ -10,25 +10,28 @@ describe('queryCache', () => {
1010
test('setQueryData does not crash if query could not be found', () => {
1111
const user = { userId: 1 }
1212
expect(() =>
13-
queryCache.setQueryData(['USER', user], (prevUser?: typeof user) => ({
14-
...prevUser!,
15-
name: 'Edvin',
16-
}))
13+
defaultQueryCache.setQueryData(
14+
['USER', user],
15+
(prevUser?: typeof user) => ({
16+
...prevUser!,
17+
name: 'Edvin',
18+
})
19+
)
1720
).not.toThrow()
1821
})
1922

2023
test('setQueryData does not crash when variable is null', () => {
21-
queryCache.setQueryData(['USER', { userId: null }], 'Old Data')
24+
defaultQueryCache.setQueryData(['USER', { userId: null }], 'Old Data')
2225

2326
expect(() =>
24-
queryCache.setQueryData(['USER', { userId: null }], 'New Data')
27+
defaultQueryCache.setQueryData(['USER', { userId: null }], 'New Data')
2528
).not.toThrow()
2629
})
2730

2831
// https://github.com/tannerlinsley/react-query/issues/652
2932
test('prefetchQuery should not retry by default', async () => {
3033
await expect(
31-
queryCache.prefetchQuery(
34+
defaultQueryCache.prefetchQuery(
3235
'key',
3336
async () => {
3437
throw new Error('error')
@@ -41,16 +44,16 @@ describe('queryCache', () => {
4144

4245
test('prefetchQuery returns the cached data on cache hits', async () => {
4346
const fetchFn = () => Promise.resolve('data')
44-
const first = await queryCache.prefetchQuery('key', fetchFn)
45-
const second = await queryCache.prefetchQuery('key', fetchFn)
47+
const first = await defaultQueryCache.prefetchQuery('key', fetchFn)
48+
const second = await defaultQueryCache.prefetchQuery('key', fetchFn)
4649

4750
expect(second).toBe(first)
4851
})
4952

5053
test('prefetchQuery should not force fetch', async () => {
51-
queryCache.setQueryData('key', 'og', { staleTime: 100 })
54+
defaultQueryCache.setQueryData('key', 'og', { staleTime: 100 })
5255
const fetchFn = () => Promise.resolve('new')
53-
const first = await queryCache.prefetchQuery(
56+
const first = await defaultQueryCache.prefetchQuery(
5457
'key',
5558
fetchFn,
5659
{
@@ -65,7 +68,7 @@ describe('queryCache', () => {
6568

6669
test('prefetchQuery should throw error when throwOnError is true', async () => {
6770
await expect(
68-
queryCache.prefetchQuery(
71+
defaultQueryCache.prefetchQuery(
6972
'key',
7073
async () => {
7174
throw new Error('error')
@@ -81,9 +84,9 @@ describe('queryCache', () => {
8184
test('should notify listeners when new query is added', async () => {
8285
const callback = jest.fn()
8386

84-
queryCache.subscribe(callback)
87+
defaultQueryCache.subscribe(callback)
8588

86-
queryCache.prefetchQuery('test', () => 'data')
89+
defaultQueryCache.prefetchQuery('test', () => 'data')
8790

8891
await sleep(100)
8992

@@ -93,91 +96,95 @@ describe('queryCache', () => {
9396
test('should include the queryCache and query when notifying listeners', async () => {
9497
const callback = jest.fn()
9598

96-
queryCache.subscribe(callback)
99+
defaultQueryCache.subscribe(callback)
97100

98-
queryCache.prefetchQuery('test', () => 'data')
99-
const query = queryCache.getQuery('test')
101+
defaultQueryCache.prefetchQuery('test', () => 'data')
102+
const query = defaultQueryCache.getQuery('test')
100103

101104
await sleep(100)
102105

103-
expect(callback).toHaveBeenCalledWith(queryCache, query)
106+
expect(callback).toHaveBeenCalledWith(defaultQueryCache, query)
104107
})
105108

106109
test('should notify subscribers when new query with initialData is added', async () => {
107110
const callback = jest.fn()
108111

109-
queryCache.subscribe(callback)
112+
defaultQueryCache.subscribe(callback)
110113

111-
queryCache.prefetchQuery('test', () => 'data', { initialData: 'initial' })
114+
defaultQueryCache.prefetchQuery('test', () => 'data', {
115+
initialData: 'initial',
116+
})
112117

113118
await sleep(100)
114119

115120
expect(callback).toHaveBeenCalled()
116121
})
117122

118123
test('setQueryData creates a new query if query was not found', () => {
119-
queryCache.setQueryData('foo', 'bar')
124+
defaultQueryCache.setQueryData('foo', 'bar')
120125

121-
expect(queryCache.getQueryData('foo')).toBe('bar')
126+
expect(defaultQueryCache.getQueryData('foo')).toBe('bar')
122127
})
123128

124129
test('setQueryData creates a new query if query was not found', () => {
125-
queryCache.setQueryData('baz', 'qux')
130+
defaultQueryCache.setQueryData('baz', 'qux')
126131

127-
expect(queryCache.getQueryData('baz')).toBe('qux')
132+
expect(defaultQueryCache.getQueryData('baz')).toBe('qux')
128133
})
129134

130135
test('removeQueries does not crash when exact is provided', async () => {
131136
const fetchFn = () => Promise.resolve('data')
132137

133138
// check the query was added to the cache
134-
await queryCache.prefetchQuery('key', fetchFn)
135-
expect(queryCache.getQuery('key')).toBeTruthy()
139+
await defaultQueryCache.prefetchQuery('key', fetchFn)
140+
expect(defaultQueryCache.getQuery('key')).toBeTruthy()
136141

137142
// check the error doesn't occur
138-
expect(() => queryCache.removeQueries('key', { exact: true })).not.toThrow()
143+
expect(() =>
144+
defaultQueryCache.removeQueries('key', { exact: true })
145+
).not.toThrow()
139146

140147
// check query was successful removed
141-
expect(queryCache.getQuery('key')).toBeFalsy()
148+
expect(defaultQueryCache.getQuery('key')).toBeFalsy()
142149
})
143150

144151
test('setQueryData should schedule stale timeout, if staleTime is set', async () => {
145-
queryCache.setQueryData('key', 'test data', { staleTime: 10 })
152+
defaultQueryCache.setQueryData('key', 'test data', { staleTime: 10 })
146153
// @ts-expect-error
147-
expect(queryCache.getQuery('key')!.staleTimeout).not.toBeUndefined()
154+
expect(defaultQueryCache.getQuery('key')!.staleTimeout).not.toBeUndefined()
148155
})
149156

150157
test('setQueryData should not schedule stale timeout by default', async () => {
151-
queryCache.setQueryData('key', 'test data')
158+
defaultQueryCache.setQueryData('key', 'test data')
152159
// @ts-expect-error
153-
expect(queryCache.getQuery('key')!.staleTimeout).toBeUndefined()
160+
expect(defaultQueryCache.getQuery('key')!.staleTimeout).toBeUndefined()
154161
})
155162

156163
test('setQueryData should not schedule stale timeout, if staleTime is set to `Infinity`', async () => {
157-
queryCache.setQueryData('key', 'test data', { staleTime: Infinity })
164+
defaultQueryCache.setQueryData('key', 'test data', { staleTime: Infinity })
158165
// @ts-expect-error
159-
expect(queryCache.getQuery('key')!.staleTimeout).toBeUndefined()
166+
expect(defaultQueryCache.getQuery('key')!.staleTimeout).toBeUndefined()
160167
})
161168

162169
test('setQueryData schedules stale timeouts appropriately', async () => {
163-
queryCache.setQueryData('key', 'test data', { staleTime: 100 })
170+
defaultQueryCache.setQueryData('key', 'test data', { staleTime: 100 })
164171

165-
expect(queryCache.getQuery('key')!.state.data).toEqual('test data')
166-
expect(queryCache.getQuery('key')!.state.isStale).toEqual(false)
172+
expect(defaultQueryCache.getQuery('key')!.state.data).toEqual('test data')
173+
expect(defaultQueryCache.getQuery('key')!.state.isStale).toEqual(false)
167174

168175
await new Promise(resolve => setTimeout(resolve, 100))
169176

170-
expect(queryCache.getQuery('key')!.state.isStale).toEqual(true)
177+
expect(defaultQueryCache.getQuery('key')!.state.isStale).toEqual(true)
171178
})
172179

173180
test('setQueryData updater function works as expected', () => {
174181
const updater = jest.fn(oldData => `new data + ${oldData}`)
175182

176-
queryCache.setQueryData('updater', 'test data')
177-
queryCache.setQueryData('updater', updater)
183+
defaultQueryCache.setQueryData('updater', 'test data')
184+
defaultQueryCache.setQueryData('updater', updater)
178185

179186
expect(updater).toHaveBeenCalled()
180-
expect(queryCache.getQuery('updater')!.state.data).toEqual(
187+
expect(defaultQueryCache.getQuery('updater')!.state.data).toEqual(
181188
'new data + test data'
182189
)
183190
})
@@ -186,33 +193,35 @@ describe('queryCache', () => {
186193
const fetchData1 = () => Promise.resolve('data1')
187194
const fetchData2 = () => Promise.resolve('data2')
188195
const fetchDifferentData = () => Promise.resolve('data3')
189-
await queryCache.prefetchQuery(['data', { page: 1 }], fetchData1)
190-
await queryCache.prefetchQuery(['data', { page: 2 }], fetchData2)
191-
await queryCache.prefetchQuery(['differentData'], fetchDifferentData)
192-
const queries = queryCache.getQueries('data')
196+
await defaultQueryCache.prefetchQuery(['data', { page: 1 }], fetchData1)
197+
await defaultQueryCache.prefetchQuery(['data', { page: 2 }], fetchData2)
198+
await defaultQueryCache.prefetchQuery(['differentData'], fetchDifferentData)
199+
const queries = defaultQueryCache.getQueries('data')
193200
const data = queries.map(query => query.state.data)
194201
expect(data).toEqual(['data1', 'data2'])
195202
})
196203

197204
test('stale timeout dispatch is not called if query is no longer in the query cache', async () => {
198205
const queryKey = 'key'
199206
const fetchData = () => Promise.resolve('data')
200-
await queryCache.prefetchQuery(queryKey, fetchData, { staleTime: 100 })
201-
const query = queryCache.getQuery(queryKey)
207+
await defaultQueryCache.prefetchQuery(queryKey, fetchData, {
208+
staleTime: 100,
209+
})
210+
const query = defaultQueryCache.getQuery(queryKey)
202211
expect(query!.state.isStale).toBe(false)
203-
queryCache.removeQueries(queryKey)
212+
defaultQueryCache.removeQueries(queryKey)
204213
await sleep(50)
205214
expect(query!.state.isStale).toBe(false)
206215
})
207216

208217
test('query interval is cleared when unsubscribed to a refetchInterval query', async () => {
209218
const queryKey = 'key'
210219
const fetchData = () => Promise.resolve('data')
211-
await queryCache.prefetchQuery(queryKey, fetchData, {
220+
await defaultQueryCache.prefetchQuery(queryKey, fetchData, {
212221
cacheTime: 0,
213222
refetchInterval: 1,
214223
})
215-
const query = queryCache.getQuery(queryKey)!
224+
const query = defaultQueryCache.getQuery(queryKey)!
216225
const instance = query.subscribe()
217226
instance.updateConfig(query.config)
218227
// @ts-expect-error
@@ -221,47 +230,82 @@ describe('queryCache', () => {
221230
// @ts-expect-error
222231
expect(instance.refetchIntervalId).toBeUndefined()
223232
await sleep(10)
224-
expect(queryCache.getQuery(queryKey)).toBeUndefined()
233+
expect(defaultQueryCache.getQuery(queryKey)).toBeUndefined()
225234
})
226235

227236
test('query is garbage collected when unsubscribed to', async () => {
228237
const queryKey = 'key'
229238
const fetchData = () => Promise.resolve('data')
230-
await queryCache.prefetchQuery(queryKey, fetchData, { cacheTime: 0 })
231-
const query = queryCache.getQuery(queryKey)!
239+
await defaultQueryCache.prefetchQuery(queryKey, fetchData, { cacheTime: 0 })
240+
const query = defaultQueryCache.getQuery(queryKey)!
232241
expect(query.state.markedForGarbageCollection).toBe(false)
233242
const instance = query.subscribe()
234243
instance.unsubscribe()
235244
expect(query.state.markedForGarbageCollection).toBe(true)
236245
await sleep(10)
237-
expect(queryCache.getQuery(queryKey)).toBeUndefined()
246+
expect(defaultQueryCache.getQuery(queryKey)).toBeUndefined()
238247
})
239248

240249
test('query is not garbage collected unless markedForGarbageCollection is true', async () => {
241250
const queryKey = 'key'
242251
const fetchData = () => Promise.resolve(undefined)
243-
await queryCache.prefetchQuery(queryKey, fetchData, { cacheTime: 0 })
244-
const query = queryCache.getQuery(queryKey)!
252+
await defaultQueryCache.prefetchQuery(queryKey, fetchData, { cacheTime: 0 })
253+
const query = defaultQueryCache.getQuery(queryKey)!
245254
expect(query.state.markedForGarbageCollection).toBe(false)
246255
const instance = query.subscribe()
247256
instance.unsubscribe()
248257
expect(query.state.markedForGarbageCollection).toBe(true)
249-
queryCache.clear({ notify: false })
250-
queryCache.setQueryData(queryKey, 'data')
258+
defaultQueryCache.clear({ notify: false })
259+
defaultQueryCache.setQueryData(queryKey, 'data')
251260
await sleep(10)
252-
const newQuery = queryCache.getQuery(queryKey)!
261+
const newQuery = defaultQueryCache.getQuery(queryKey)!
253262
expect(newQuery.state.markedForGarbageCollection).toBe(false)
254263
expect(newQuery.state.data).toBe('data')
255264
})
256265

257-
test('makeQueryCache merges defaultConfig so providing a queryFn does not overwrite the default queryKeySerializerFn', async () => {
258-
const queryFn = () => 'data'
259-
const queryCache = makeQueryCache({
260-
defaultConfig: { queries: { queryFn } },
266+
describe('makeQueryCache', () => {
267+
test('merges defaultConfig so providing a queryFn does not overwrite the default queryKeySerializerFn', async () => {
268+
const queryFn = () => 'data'
269+
const queryCache = makeQueryCache({
270+
defaultConfig: { queries: { queryFn } },
271+
})
272+
273+
expect(() => queryCache.buildQuery('test')).not.toThrow(
274+
'config.queryKeySerializerFn is not a function'
275+
)
261276
})
262277

263-
expect(() => queryCache.buildQuery('test')).not.toThrow(
264-
'config.queryKeySerializerFn is not a function'
265-
)
278+
test('merges defaultConfig when query is added to cache', async () => {
279+
const queryCache = makeQueryCache({
280+
defaultConfig: {
281+
queries: { refetchOnMount: false, staleTime: Infinity },
282+
},
283+
})
284+
285+
const queryKey = 'key'
286+
const fetchData = () => Promise.resolve(undefined)
287+
await queryCache.prefetchQuery(queryKey, fetchData)
288+
const newQuery = queryCache.getQuery(queryKey)
289+
expect(newQuery?.config.staleTime).toBe(Infinity)
290+
expect(newQuery?.config.refetchOnMount).toBe(false)
291+
})
292+
293+
test('built queries are referencing the correct queryCache', () => {
294+
const queryCache = makeQueryCache()
295+
const query = queryCache.buildQuery('test')
296+
297+
expect(query.queryCache).toBe(queryCache)
298+
})
299+
300+
test('notifyGlobalListeners passes the same instance', () => {
301+
const queryCache = makeQueryCache()
302+
const subscriber = jest.fn()
303+
const unsubscribe = queryCache.subscribe(subscriber)
304+
const query = queryCache.buildQuery('test')
305+
query.setData('foo');
306+
expect(subscriber).toHaveBeenCalledWith(queryCache, query)
307+
308+
unsubscribe()
309+
})
266310
})
267311
})

0 commit comments

Comments
 (0)