Repository: tannerlinsley/react-query (ts)

Issue:
Refetching query doesnt set error back to null
### Describe the bug

When query refetching happens, for example on window focus, error object is not cleared even though types say that when isLoading is set to true, error is always null. Screenshot attached

### Your Example Website or App

https://codesandbox.io/s/boring-paper-l7jf0?file=/src/use-subscription.tsx

### Steps to reproduce

Open the console and watch for variables being displayed, once you refocus back to the window both isLoading and error are displayed.

### Expected behavior

- remove the error when we go to loading state.
- change the types so that they reflect that you can have an error in loading state, too.

### How often does this bug happen?

Every time

### Screenshots or Videos

![image](https://user-images.githubusercontent.com/12643248/145860235-9920eae5-ed1a-4227-b442-91fdc5ea12bd.png)

### Platform

- OS: [e.g. macOS, Windows, Linux, iOS, Android]
- Browser: [e.g. Chrome, Safari, Firefox, React Native]
- Version: [e.g. 91.1]


### Additional context

_No response_

Pull request:
fix(query): set error to null when going to loading state
to be aligned with the types, as `loading` cannot have an `error` set.

closes #3090 

Patch:
diff --git a/src/core/query.ts b/src/core/query.ts
index 1b5a3854a..3ad311054 100644
--- a/src/core/query.ts
+++ b/src/core/query.ts
@@ -584,7 +584,10 @@ export class Query<
           fetchMeta: action.meta ?? null,
           isFetching: true,
           isPaused: false,
-          status: !state.dataUpdatedAt ? 'loading' : state.status,
+          ...(!state.dataUpdatedAt && {
+            error: null,
+            status: 'loading',
+          }),
         }
       case 'success':
         return {


Test patch:
diff --git a/src/react/tests/useQuery.test.tsx b/src/react/tests/useQuery.test.tsx
index 7400ebee0..5170c51c5 100644
--- a/src/react/tests/useQuery.test.tsx
+++ b/src/react/tests/useQuery.test.tsx
@@ -4505,4 +4505,80 @@ describe('useQuery', () => {
 
     consoleMock.mockRestore()
   })
+
+  it('should have no error in loading state when refetching after error occurred', async () => {
+    const consoleMock = mockConsoleError()
+    const key = queryKey()
+    const states: UseQueryResult<number>[] = []
+    const error = new Error('oops')
+
+    let count = 0
+
+    function Page() {
+      const state = useQuery(
+        key,
+        async () => {
+          await sleep(10)
+          if (count === 0) {
+            count++
+            throw error
+          }
+          return 5
+        },
+        {
+          retry: false,
+        }
+      )
+
+      states.push(state)
+
+      if (state.isLoading) {
+        return <div>status: loading</div>
+      }
+      if (state.error instanceof Error) {
+        return (
+          <div>
+            <div>error</div>
+            <button onClick={() => state.refetch()}>refetch</button>
+          </div>
+        )
+      }
+      return <div>data: {state.data}</div>
+    }
+
+    const rendered = renderWithClient(queryClient, <Page />)
+
+    await waitFor(() => rendered.getByText('error'))
+
+    fireEvent.click(rendered.getByRole('button', { name: 'refetch' }))
+    await waitFor(() => rendered.getByText('data: 5'))
+
+    await waitFor(() => expect(states.length).toBe(4))
+
+    expect(states[0]).toMatchObject({
+      status: 'loading',
+      data: undefined,
+      error: null,
+    })
+
+    expect(states[1]).toMatchObject({
+      status: 'error',
+      data: undefined,
+      error,
+    })
+
+    expect(states[2]).toMatchObject({
+      status: 'loading',
+      data: undefined,
+      error: null,
+    })
+
+    expect(states[3]).toMatchObject({
+      status: 'success',
+      data: 5,
+      error: null,
+    })
+
+    consoleMock.mockRestore()
+  })
 })