Repository: reduxjs/redux-toolkit

Problem statement:
[RTK-Query]: `useQuery` hook does not refetch after `resetApiState` (2)
### Description:
This issue appears to be a bug in RTK-Query, which should have been resolved by #1735 and #3333. However, it appears that the problem persists.

### Reproduction Steps:
1. Access the following example showcasing the issue: [CodeSandbox](https://codesandbox.io/s/rtkq-resetapistate-query-2mxs7f)
2. Click on the "Rerender Component" button.
3. Click on the "Reset Api State" button.

### Expected Behavior:
After clicking "Reset API State," the request should not remain stuck in a pending status. Instead, it should automatically re-fetch the query. Currently, the request remains pending until the component is re-rendered. Even if we attempt to manually refetch, the query is executed, but the result remains pending.


Hints:
Yup, I can see that. Weird that it only happens after a rerender 🤔 
@phryneas 

Is there any fixes for this?
I have same issue on my project
Same thing in my project.

Patch:
diff --git a/packages/toolkit/src/query/react/buildHooks.ts b/packages/toolkit/src/query/react/buildHooks.ts
--- a/packages/toolkit/src/query/react/buildHooks.ts
+++ b/packages/toolkit/src/query/react/buildHooks.ts
@@ -1661,8 +1661,6 @@ export function buildHooks<Definitions extends EndpointDefinitions>({
       skipPollingIfUnfocused,
     })
 
-    const lastRenderHadSubscription = useRef(false)
-
     const initialPageParam = (rest as UseInfiniteQuerySubscriptionOptions<any>)
       .initialPageParam
     const stableInitialPageParam = useShallowStableValue(initialPageParam)
@@ -1686,11 +1684,7 @@ export function buildHooks<Definitions extends EndpointDefinitions>({
     }
 
     const subscriptionRemoved =
-      !currentRenderHasSubscription && lastRenderHadSubscription.current
-
-    usePossiblyImmediateEffect(() => {
-      lastRenderHadSubscription.current = currentRenderHasSubscription
-    })
+      !currentRenderHasSubscription && promiseRef.current !== undefined
 
     usePossiblyImmediateEffect((): void | undefined => {
       if (subscriptionRemoved) {


Test patch:
diff --git a/packages/toolkit/src/query/tests/buildHooks.test.tsx b/packages/toolkit/src/query/tests/buildHooks.test.tsx
--- a/packages/toolkit/src/query/tests/buildHooks.test.tsx
+++ b/packages/toolkit/src/query/tests/buildHooks.test.tsx
@@ -902,6 +902,71 @@ describe('hooks tests', () => {
           status: 'uninitialized',
         })
       })
+
+      test('hook should not be stuck loading post resetApiState after re-render', async () => {
+        const user = userEvent.setup()
+
+        function QueryComponent() {
+          const { isLoading, data } = api.endpoints.getUser.useQuery(1)
+
+          if (isLoading) {
+            return <p>Loading...</p>
+          }
+
+          return <p>{data?.name}</p>
+        }
+
+        function Wrapper() {
+          const [open, setOpen] = useState(true)
+
+          const handleRerender = () => {
+            setOpen(false)
+            setTimeout(() => {
+              setOpen(true)
+            }, 1000)
+          }
+
+          const handleReset = () => {
+            storeRef.store.dispatch(api.util.resetApiState())
+          }
+
+          return (
+            <>
+              <button onClick={handleRerender} aria-label="Rerender component">
+                Rerender
+              </button>
+              {open ? (
+                <div>
+                  <button onClick={handleReset} aria-label="Reset API state">
+                    Reset
+                  </button>
+
+                  <QueryComponent />
+                </div>
+              ) : null}
+            </>
+          )
+        }
+
+        render(<Wrapper />, { wrapper: storeRef.wrapper })
+
+        await user.click(
+          screen.getByRole('button', { name: /Rerender component/i }),
+        )
+        await waitFor(() => {
+          expect(screen.getByText('Timmy')).toBeTruthy()
+        })
+
+        await user.click(
+          screen.getByRole('button', { name: /reset api state/i }),
+        )
+        await waitFor(() => {
+          expect(screen.queryByText('Loading...')).toBeNull()
+        })
+        await waitFor(() => {
+          expect(screen.getByText('Timmy')).toBeTruthy()
+        })
+      })
     })
 
     test('useQuery refetch method returns a promise that resolves with the result', async () => {
diff --git a/packages/toolkit/src/query/tests/createApi.test.ts b/packages/toolkit/src/query/tests/createApi.test.ts
--- a/packages/toolkit/src/query/tests/createApi.test.ts
+++ b/packages/toolkit/src/query/tests/createApi.test.ts
@@ -1181,7 +1181,7 @@ describe('timeout behavior', () => {
       http.get(
         'https://example.com/success',
         async () => {
-          await delay(10)
+          await delay(50)
           return HttpResponse.json({ value: 'failed' }, { status: 500 })
         },
         { once: true },