Repository: tannerlinsley/react-query (ts)

Issue:
setQueryData incorrectly sets isFetching to false
### Describe the bug

If `setQueryData` is invoked while a query is fetching, `isFetching` automatically goes to `false`.

Quoting @TkDodo (see [his comment](https://github.com/tannerlinsley/react-query/issues/3579#issuecomment-1120430029) in #3579 ), when `setQueryData` is called
> only the status, data and dataUpdatedAt fields should be set



### Your minimal, reproducible example

https://codesandbox.io/s/setquerydata-and-isfetching-bug-gck1zp?file=/src/App.js

### Steps to reproduce

1. Go to [the MWE](https://codesandbox.io/s/setquerydata-and-isfetching-bug-gck1zp?file=/src/App.js)
2. Click "Refetch", and note that "isFetching: true" is displayed
3. Before the query ends (you have 5 seconds), click "Manually update data" 
4.  "isFetching: false" is displayed, even though the query is still being fetched 🐛🐛🐛

### Expected behavior

Calling `setQueryData` shouldn't change the value of `isFetching` 

### How often does this bug happen?

Every time

### Screenshots or Videos


https://user-images.githubusercontent.com/4582440/167303377-e254b757-d84a-480f-9cdf-0abab3227f9a.mov



### Platform

- OS: MacOs
- Browser: Chrome
- Version: 100

### react-query version

3.39.0 and also 4.0.0-beta.9

### TypeScript version

_No response_

### Additional context

_No response_

Pull request:
fix(query): updating with setQueryData should not affect fetchStatus
queries can be fetching _while_ we are making a manual update are still fetching, so we have to set fields that affect the fetch conditionally (fetchStatus, fetchFailureCount)

fixes #3594 

Patch:
diff --git a/src/core/query.ts b/src/core/query.ts
index 75bf733f5..ce70b56dc 100644
--- a/src/core/query.ts
+++ b/src/core/query.ts
@@ -98,7 +98,7 @@ interface SuccessAction<TData> {
   data: TData | undefined
   type: 'success'
   dataUpdatedAt?: number
-  notifySuccess?: boolean
+  manual?: boolean
 }
 
 interface ErrorAction<TError> {
@@ -195,10 +195,7 @@ export class Query<
     }
   }
 
-  setData(
-    data: TData,
-    options?: SetDataOptions & { notifySuccess: boolean }
-  ): TData {
+  setData(data: TData, options?: SetDataOptions & { manual: boolean }): TData {
     const prevData = this.state.data
 
     // Use prev data if an isDataEqual function is defined and returns `true`
@@ -214,7 +211,7 @@ export class Query<
       data,
       type: 'success',
       dataUpdatedAt: options?.updatedAt,
-      notifySuccess: options?.notifySuccess,
+      manual: options?.manual,
     })
 
     return data
@@ -538,10 +535,12 @@ export class Query<
             dataUpdateCount: state.dataUpdateCount + 1,
             dataUpdatedAt: action.dataUpdatedAt ?? Date.now(),
             error: null,
-            fetchFailureCount: 0,
             isInvalidated: false,
-            fetchStatus: 'idle',
             status: 'success',
+            ...(!action.manual && {
+              fetchStatus: 'idle',
+              fetchFailureCount: 0,
+            }),
           }
         case 'error':
           const error = action.error as unknown
diff --git a/src/core/queryClient.ts b/src/core/queryClient.ts
index 2e64194f2..15afee437 100644
--- a/src/core/queryClient.ts
+++ b/src/core/queryClient.ts
@@ -143,7 +143,7 @@ export class QueryClient {
     const defaultedOptions = this.defaultQueryOptions(parsedOptions)
     return this.queryCache
       .build(this, defaultedOptions)
-      .setData(data, { ...options, notifySuccess: false })
+      .setData(data, { ...options, manual: true })
   }
 
   setQueriesData<TData>(
diff --git a/src/core/queryObserver.ts b/src/core/queryObserver.ts
index 6fbb09449..f5ca479e0 100644
--- a/src/core/queryObserver.ts
+++ b/src/core/queryObserver.ts
@@ -650,7 +650,7 @@ export class QueryObserver<
     const notifyOptions: NotifyOptions = {}
 
     if (action.type === 'success') {
-      notifyOptions.onSuccess = action.notifySuccess ?? true
+      notifyOptions.onSuccess = !action.manual
     } else if (action.type === 'error' && !isCancelledError(action.error)) {
       notifyOptions.onError = true
     }


Test patch:
diff --git a/src/core/tests/queryClient.test.tsx b/src/core/tests/queryClient.test.tsx
index aaf0a07e3..e08c454c2 100644
--- a/src/core/tests/queryClient.test.tsx
+++ b/src/core/tests/queryClient.test.tsx
@@ -356,6 +356,29 @@ describe('queryClient', () => {
 
       expect(queryCache.find(key)!.state.data).toBe(newData)
     })
+
+    test('should not set isFetching to false', async () => {
+      const key = queryKey()
+      queryClient.prefetchQuery(key, async () => {
+        await sleep(10)
+        return 23
+      })
+      expect(queryClient.getQueryState(key)).toMatchObject({
+        data: undefined,
+        fetchStatus: 'fetching',
+      })
+      queryClient.setQueryData(key, 42)
+      expect(queryClient.getQueryState(key)).toMatchObject({
+        data: 42,
+        fetchStatus: 'fetching',
+      })
+      await waitFor(() =>
+        expect(queryClient.getQueryState(key)).toMatchObject({
+          data: 23,
+          fetchStatus: 'idle',
+        })
+      )
+    })
   })
 
   describe('setQueriesData', () => {