Repository: tannerlinsley/react-query
Pull request #765 (2020-07-16 22:37:09)

feat(queryCache): pass query to subscribers
Any cache update triggered by a query will pass the query as the second argument to subscribers.
This enables executing side-effects for specific query updates.

BREAKING CHANGE: none

vercel[bot]: 
This pull request is being automatically deployed with Vercel ([learn more](https://vercel.link/github-learn-more)).
To see the status of your deployment, click on the icon next to each commit.
	

Patch:
diff --git a/docs/src/pages/docs/api.md b/docs/src/pages/docs/api.md
index 3f37649b3..68d7c06bb 100644
--- a/docs/src/pages/docs/api.md
+++ b/docs/src/pages/docs/api.md
@@ -580,15 +580,16 @@ The `subscribe` method can be used to subscribe to the query cache as a whole an
 ```js
 import { queryCache } from 'react-query'
 
-const callback = cache => {}
+const callback = (cache, query) => {}
 
 const unsubscribe = queryCache.subscribe(callback)
 ```
 
 **Options**
 
-- `callback: Function(queryCache) => void`
+- `callback: Function(queryCache, query?) => void`
   - This function will be called with the query cache any time it is updated via its tracked update mechanisms (eg, `query.setState`, `queryCache.removeQueries`, etc). Out of scope mutations to the queryCache are not encouraged and will not fire subscription callbacks
+  - Additionally, for updates to the cache triggered by a specific query, the `query` will be passed as the second argument to the callback
 
 **Returns**
 
diff --git a/src/core/query.js b/src/core/query.js
index cd604769e..74363f838 100644
--- a/src/core/query.js
+++ b/src/core/query.js
@@ -65,7 +65,7 @@ export function makeQuery({
   query.dispatch = action => {
     query.state = queryReducer(query.state, action)
     query.instances.forEach(d => d.onStateUpdate(query.state))
-    notifyGlobalListeners()
+    notifyGlobalListeners(query)
   }
 
   query.scheduleStaleTimeout = () => {
@@ -158,7 +158,7 @@ export function makeQuery({
     query.cancel()
     query.dispatch = noop
     delete queryCache.queries[query.queryHash]
-    notifyGlobalListeners()
+    notifyGlobalListeners(query)
   }
 
   query.subscribe = (onStateUpdate = noop) => {
diff --git a/src/core/queryCache.js b/src/core/queryCache.js
index 813b7ef47..0134dda77 100644
--- a/src/core/queryCache.js
+++ b/src/core/queryCache.js
@@ -17,7 +17,7 @@ export function makeQueryCache({ frozen = isServer, defaultConfig } = {}) {
   const globalListeners = []
 
   const configRef = defaultConfig
-    ? { current: { ...defaultConfigRef.current, ...defaultConfig }}
+    ? { current: { ...defaultConfigRef.current, ...defaultConfig } }
     : defaultConfigRef
 
   const queryCache = {
@@ -25,13 +25,13 @@ export function makeQueryCache({ frozen = isServer, defaultConfig } = {}) {
     isFetching: 0,
   }
 
-  const notifyGlobalListeners = () => {
+  const notifyGlobalListeners = query => {
     queryCache.isFetching = Object.values(queryCache.queries).reduce(
       (acc, query) => (query.state.isFetching ? acc + 1 : acc),
       0
     )
 
-    globalListeners.forEach(d => d(queryCache))
+    globalListeners.forEach(d => d(queryCache, query))
   }
 
   queryCache.subscribe = cb => {
diff --git a/types/index.d.ts b/types/index.d.ts
index 5a2c8243e..dc6e925cc 100644
--- a/types/index.d.ts
+++ b/types/index.d.ts
@@ -627,7 +627,7 @@ export interface QueryCache {
     { exact }?: { exact?: boolean }
   ): void
   isFetching: number
-  subscribe(callback: (queryCache: QueryCache) => void): () => void
+  subscribe(callback: (queryCache: QueryCache, query?: CachedQuery<unknown>) => void): () => void
   clear(options?: { notify?: boolean }): void
   resetErrorBoundaries: () => void
 }


Test patch:
diff --git a/src/core/tests/queryCache.test.js b/src/core/tests/queryCache.test.js
index 74feba9ed..cc5bdff95 100644
--- a/src/core/tests/queryCache.test.js
+++ b/src/core/tests/queryCache.test.js
@@ -86,6 +86,17 @@ describe('queryCache', () => {
     expect(callback).toHaveBeenCalled()
   })
 
+  test('should include the queryCache and query when notifying listeners', () => {
+    const callback = jest.fn()
+
+    queryCache.subscribe(callback)
+
+    queryCache.prefetchQuery('test', () => 'data')
+    const query = queryCache.getQuery('test')
+
+    expect(callback).toHaveBeenCalledWith(queryCache, query)
+  })
+
   test('should notify subscribers when new query with initialData is added', async () => {
     const callback = jest.fn()