Repository: tannerlinsley/react-query
Pull request #3007 (2021-11-22 16:35:03)

fix(query): make sure prefetched queries can be garbage collected

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 below or on the icon next to each commit.

🔍 Inspect: [https://vercel.com/tanstack/react-query/6xgKzQpwheQNXZnF6cCTkGjJTaFY](https://vercel.com/tanstack/react-query/6xgKzQpwheQNXZnF6cCTkGjJTaFY)  
✅ Preview: *In Progress*


codesandbox[bot]: This pull request is automatically built and testable in [CodeSandbox](https://codesandbox.io).

  To see build info of the built libraries, click [here](https://ci.codesandbox.io/status/tannerlinsley/react-query/pr/3007/builds/190781) or the icon next to each commit SHA.

Latest deployment of this branch, based on commit 09c4fcf423b19a3bdd49d7ea07ca9007ad449d96:

|Sandbox| Source |
|--|--|
|[tannerlinsley/react-query](https://codesandbox.io/s/tannerlinsley-react-query-86r2f)| Configuration |
|[tannerlinsley/react-query: basic-typescript](https://codesandbox.io/s/tannerlinsley-react-query-basic-typescript-cpfc5)| Configuration |

codecov[bot]: # [Codecov](https://codecov.io/gh/tannerlinsley/react-query/pull/3007?src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Tanner+Linsley) Report
> Merging [#3007](https://codecov.io/gh/tannerlinsley/react-query/pull/3007?src=pr&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Tanner+Linsley) (09c4fcf) into [master](https://codecov.io/gh/tannerlinsley/react-query/commit/27e72de2677031779cad62ae346a5a6a0945603e?el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Tanner+Linsley) (27e72de) will **increase** coverage by `0.00%`.
> The diff coverage is `100.00%`.

[![Impacted file tree graph](https://codecov.io/gh/tannerlinsley/react-query/pull/3007/graphs/tree.svg?width=650&height=150&src=pr&token=jqEbswkEDQ&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Tanner+Linsley)](https://codecov.io/gh/tannerlinsley/react-query/pull/3007?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Tanner+Linsley)

```diff
@@           Coverage Diff           @@
##           master    #3007   +/-   ##
=======================================
  Coverage   96.41%   96.42%           
=======================================
  Files          45       45           
  Lines        2233     2237    +4     
  Branches      640      641    +1     
=======================================
+ Hits         2153     2157    +4     
  Misses         77       77           
  Partials        3        3           
```


| [Impacted Files](https://codecov.io/gh/tannerlinsley/react-query/pull/3007?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Tanner+Linsley) | Coverage Δ | |
|---|---|---|
| [src/core/query.ts](https://codecov.io/gh/tannerlinsley/react-query/pull/3007/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Tanner+Linsley#diff-c3JjL2NvcmUvcXVlcnkudHM=) | `100.00% <100.00%> (ø)` | |

------

[Continue to review full report at Codecov](https://codecov.io/gh/tannerlinsley/react-query/pull/3007?src=pr&el=continue&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Tanner+Linsley).
> **Legend** - [Click here to learn more](https://docs.codecov.io/docs/codecov-delta?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Tanner+Linsley)
> `Δ = absolute <relative> (impact)`, `ø = not affected`, `? = missing data`
> Powered by [Codecov](https://codecov.io/gh/tannerlinsley/react-query/pull/3007?src=pr&el=footer&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Tanner+Linsley). Last update [27e72de...09c4fcf](https://codecov.io/gh/tannerlinsley/react-query/pull/3007?src=pr&el=lastupdated&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Tanner+Linsley). Read the [comment docs](https://docs.codecov.io/docs/pull-request-comments?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Tanner+Linsley).


Patch:
diff --git a/src/core/query.ts b/src/core/query.ts
index 861da15a5..c275876e9 100644
--- a/src/core/query.ts
+++ b/src/core/query.ts
@@ -163,9 +163,11 @@ export class Query<
   private observers: QueryObserver<any, any, any, any, any>[]
   private defaultOptions?: QueryOptions<TQueryFnData, TError, TData, TQueryKey>
   private abortSignalConsumed: boolean
+  private hadObservers: boolean
 
   constructor(config: QueryConfig<TQueryFnData, TError, TData, TQueryKey>) {
     this.abortSignalConsumed = false
+    this.hadObservers = false
     this.defaultOptions = config.defaultOptions
     this.setOptions(config.options)
     this.observers = []
@@ -175,6 +177,7 @@ export class Query<
     this.initialState = config.state || this.getDefaultState(this.options)
     this.state = this.initialState
     this.meta = config.meta
+    this.scheduleGc()
   }
 
   private setOptions(
@@ -215,7 +218,9 @@ export class Query<
   private optionalRemove() {
     if (!this.observers.length) {
       if (this.state.isFetching) {
-        this.scheduleGc()
+        if (this.hadObservers) {
+          this.scheduleGc()
+        }
       } else {
         this.cache.remove(this)
       }
@@ -321,6 +326,7 @@ export class Query<
   addObserver(observer: QueryObserver<any, any, any, any, any>): void {
     if (this.observers.indexOf(observer) === -1) {
       this.observers.push(observer)
+      this.hadObservers = true
 
       // Stop the query from being garbage collected
       this.clearGcTimeout()


Test patch:
diff --git a/src/core/tests/queryClient.test.tsx b/src/core/tests/queryClient.test.tsx
index 5e0ee089a..30f8e2996 100644
--- a/src/core/tests/queryClient.test.tsx
+++ b/src/core/tests/queryClient.test.tsx
@@ -544,6 +544,21 @@ describe('queryClient', () => {
 
       consoleMock.mockRestore()
     })
+
+    test('should be garbage collected after cacheTime if unused', async () => {
+      const key = queryKey()
+
+      await queryClient.prefetchQuery(
+        key,
+        async () => {
+          return 'data'
+        },
+        { cacheTime: 10 }
+      )
+      expect(queryCache.find(key)).toBeDefined()
+      await sleep(15)
+      expect(queryCache.find(key)).not.toBeDefined()
+    })
   })
 
   describe('removeQueries', () => {