Skip to content

Commit ba01a07

Browse files
Merge branch 'master' into refetchInterval-test
2 parents e656033 + 80e82da commit ba01a07

17 files changed

+588
-119
lines changed

README.md

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -257,8 +257,10 @@ This library is being built and maintained by me, @tannerlinsley and I am always
257257
- [`queryCache.isFetching`](#querycacheisfetching)
258258
- [`queryCache.subscribe`](#querycachesubscribe)
259259
- [`queryCache.clear`](#querycacheclear)
260+
- [`useQueryCache`](#usequerycache)
260261
- [`useIsFetching`](#useisfetching)
261262
- [`ReactQueryConfigProvider`](#reactqueryconfigprovider)
263+
- [`ReactQueryCacheProvider`](#reactquerycacheprovider)
262264
- [`setConsole`](#setconsole)
263265
- [Contributors ✨](#contributors-)
264266

@@ -2524,6 +2526,18 @@ queryCache.clear()
25242526
- `queries: Array<Query>`
25252527
- This will be an array containing the queries that were found.
25262528
2529+
## `useQueryCache`
2530+
2531+
The `useQueryCache` hook returns the current queryCache instance.
2532+
2533+
```js
2534+
import { useQueryCache } from 'react-query';
2535+
2536+
const queryCache = useQueryCache()
2537+
```
2538+
2539+
If you are using the `ReactQueryCacheProvider` to set a custom cache, you cannot simply import `{ queryCache }` any more. This hook will ensure you're getting the correct instance.
2540+
25272541
## `useIsFetching`
25282542
25292543
`useIsFetching` is an optional hook that returns the `number` of the queries that your application is loading or fetching in the background (useful for app-wide loading indicators).
@@ -2584,6 +2598,29 @@ function App() {
25842598
- Must be **stable** or **memoized**. Do not create an inline object!
25852599
- For non-global properties please see their usage in both the [`useQuery` hook](#usequery) and the [`useMutation` hook](#usemutation).
25862600
2601+
## `ReactQueryCacheProvider`
2602+
2603+
`ReactQueryCacheProvider` is an optional provider component for explicitly setting the query cache used by React Query. This is useful for creating component-level caches that are not completely global, as well as making truly isolated unit tests.
2604+
2605+
```js
2606+
import { ReactQueryCacheProvider, makeQueryCache } from 'react-query';
2607+
2608+
const queryCache = makeQueryCache()
2609+
2610+
function App() {
2611+
return (
2612+
<ReactQueryCacheProvider queryCache={queryCache}>
2613+
...
2614+
</ReactQueryCacheProvider>
2615+
)
2616+
}
2617+
```
2618+
2619+
### Options
2620+
- `queryCache: Object`
2621+
- In instance of queryCache, you can use the `makeQueryCache` factory to create this.
2622+
- If not provided, a new cache will be generated.
2623+
25872624
## `setConsole`
25882625
25892626
`setConsole` is an optional utility function that allows you to replace the `console` interface used to log errors. By default, the `window.console` object is used. If no global `console` object is found in the environment, nothing will be logged.

src/index.js

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,9 @@
1-
export { queryCache } from './queryCache'
1+
export {
2+
queryCache,
3+
makeQueryCache,
4+
ReactQueryCacheProvider,
5+
useQueryCache,
6+
} from './queryCache'
27
export { ReactQueryConfigProvider } from './config'
38
export { setFocusHandler } from './setFocusHandler'
49
export { useIsFetching } from './useIsFetching'
@@ -13,4 +18,5 @@ export {
1318
statusError,
1419
stableStringify,
1520
setConsole,
21+
deepIncludes,
1622
} from './utils'

src/index.production.js

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,9 @@
1-
export { queryCache } from './queryCache'
1+
export {
2+
queryCache,
3+
makeQueryCache,
4+
ReactQueryCacheProvider,
5+
useQueryCache,
6+
} from './queryCache'
27
export { ReactQueryConfigProvider } from './config'
38
export { setFocusHandler } from './setFocusHandler'
49
export { useIsFetching } from './useIsFetching'

src/queryCache.js

Lines changed: 57 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import React from 'react'
12
import {
23
isServer,
34
functionalUpdate,
@@ -14,6 +15,42 @@ import { defaultConfigRef } from './config'
1415

1516
export const queryCache = makeQueryCache()
1617

18+
export const queryCacheContext = React.createContext(queryCache)
19+
20+
export const queryCaches = [queryCache]
21+
22+
export function useQueryCache() {
23+
return React.useContext(queryCacheContext)
24+
}
25+
26+
export function ReactQueryCacheProvider({ queryCache, children }) {
27+
const cache = React.useMemo(() => queryCache || makeQueryCache(), [
28+
queryCache,
29+
])
30+
31+
React.useEffect(() => {
32+
queryCaches.push(cache)
33+
34+
return () => {
35+
// remove the cache from the active list
36+
const i = queryCaches.indexOf(cache)
37+
if (i >= 0) {
38+
queryCaches.splice(i, 1)
39+
}
40+
// if the cache was created by us, we need to tear it down
41+
if (queryCache == null) {
42+
cache.clear()
43+
}
44+
}
45+
}, [cache, queryCache])
46+
47+
return (
48+
<queryCacheContext.Provider value={cache}>
49+
{children}
50+
</queryCacheContext.Provider>
51+
)
52+
}
53+
1754
const actionInit = {}
1855
const actionFailed = {}
1956
const actionMarkStale = {}
@@ -32,7 +69,7 @@ export function makeQueryCache() {
3269
}
3370

3471
const notifyGlobalListeners = () => {
35-
cache.isFetching = Object.values(queryCache.queries).reduce(
72+
cache.isFetching = Object.values(cache.queries).reduce(
3673
(acc, query) => (query.state.isFetching ? acc + 1 : acc),
3774
0
3875
)
@@ -87,11 +124,7 @@ export function makeQueryCache() {
87124
const foundQueries = findQueries(predicate, { exact })
88125

89126
foundQueries.forEach(query => {
90-
query.cancelled = cancelledError
91-
92-
if (query.cancelQueries) {
93-
query.cancelQueries()
94-
}
127+
query.cancel()
95128
})
96129

97130
if (foundQueries.length) {
@@ -129,6 +162,7 @@ export function makeQueryCache() {
129162
query.config = { ...query.config, ...config }
130163
} else {
131164
query = makeQuery({
165+
cache,
132166
queryKey,
133167
queryHash,
134168
queryVariables,
@@ -212,6 +246,7 @@ export function makeQueryCache() {
212246
}
213247

214248
function makeQuery(options) {
249+
const queryCache = options.cache
215250
const reducer = options.config.queryReducer || defaultQueryReducer
216251

217252
const noQueryHash = typeof options.queryHash === 'undefined'
@@ -288,6 +323,18 @@ export function makeQueryCache() {
288323
query.cancelled = null
289324
}
290325

326+
query.cancel = () => {
327+
query.cancelled = cancelledError
328+
329+
if (query.cancelPromises) {
330+
query.cancelPromises()
331+
}
332+
333+
delete query.promise
334+
335+
notifyGlobalListeners()
336+
}
337+
291338
query.updateInstance = instance => {
292339
let found = query.instances.find(d => d.id === instance.id)
293340

@@ -310,12 +357,7 @@ export function makeQueryCache() {
310357
query.instances = query.instances.filter(d => d.id !== instanceId)
311358

312359
if (!query.instances.length) {
313-
// Cancel any side-effects
314-
query.cancelled = cancelledError
315-
316-
if (query.cancelQueries) {
317-
query.cancelQueries()
318-
}
360+
query.cancel()
319361

320362
// Schedule garbage collection
321363
query.scheduleGarbageCollection()
@@ -329,16 +371,16 @@ export function makeQueryCache() {
329371
// Perform the query
330372
const promise = queryFn(...query.config.queryFnParamsFilter(args))
331373

332-
query.cancelQueries = () => promise.cancel?.()
374+
query.cancelPromises = () => promise.cancel?.()
333375

334376
const data = await promise
335377

336-
delete query.cancelQueries
378+
delete query.cancelPromises
337379
if (query.cancelled) throw query.cancelled
338380

339381
return data
340382
} catch (error) {
341-
delete query.cancelQueries
383+
delete query.cancelPromises
342384
if (query.cancelled) throw query.cancelled
343385

344386
// If we fail, increase the failureCount

src/setFocusHandler.js

Lines changed: 26 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { isOnline, isDocumentVisible, Console, isServer } from './utils'
22
import { defaultConfigRef } from './config'
3-
import { queryCache } from './queryCache'
3+
import { queryCaches } from './queryCache'
44

55
const visibilityChangeEvent = 'visibilitychange'
66
const focusEvent = 'focus'
@@ -9,29 +9,31 @@ const onWindowFocus = () => {
99
const { refetchAllOnWindowFocus } = defaultConfigRef.current
1010

1111
if (isDocumentVisible() && isOnline()) {
12-
queryCache
13-
.refetchQueries(query => {
14-
if (!query.instances.length) {
15-
return false
16-
}
17-
18-
if (query.config.manual === true) {
19-
return false
20-
}
21-
22-
if (query.shouldContinueRetryOnFocus) {
23-
// delete promise, so `fetch` will create new one
24-
delete query.promise
25-
return true
26-
}
27-
28-
if (typeof query.config.refetchOnWindowFocus === 'undefined') {
29-
return refetchAllOnWindowFocus
30-
} else {
31-
return query.config.refetchOnWindowFocus
32-
}
33-
})
34-
.catch(Console.error)
12+
queryCaches.forEach(queryCache =>
13+
queryCache
14+
.refetchQueries(query => {
15+
if (!query.instances.length) {
16+
return false
17+
}
18+
19+
if (query.config.manual === true) {
20+
return false
21+
}
22+
23+
if (query.shouldContinueRetryOnFocus) {
24+
// delete promise, so `fetch` will create new one
25+
delete query.promise
26+
return true
27+
}
28+
29+
if (typeof query.config.refetchOnWindowFocus === 'undefined') {
30+
return refetchAllOnWindowFocus
31+
} else {
32+
return query.config.refetchOnWindowFocus
33+
}
34+
})
35+
.catch(Console.error)
36+
)
3537
}
3638
}
3739

0 commit comments

Comments
 (0)