diff --git a/packages/toolkit/src/query/react/buildHooks.ts b/packages/toolkit/src/query/react/buildHooks.ts index d2432acc93..86de0e11b4 100644 --- a/packages/toolkit/src/query/react/buildHooks.ts +++ b/packages/toolkit/src/query/react/buildHooks.ts @@ -690,7 +690,7 @@ export function buildHooks({ // isFetching = true any time a request is in flight const isFetching = currentState.isLoading // isLoading = true only when loading while no data is present yet (initial load with no data in the cache) - const isLoading = !hasData && isFetching + const isLoading = (!lastResult || lastResult.isLoading || lastResult.isUninitialized) && !hasData && isFetching // isSuccess = true when data is present const isSuccess = currentState.isSuccess || (isFetching && hasData) diff --git a/packages/toolkit/src/query/tests/buildHooks.test.tsx b/packages/toolkit/src/query/tests/buildHooks.test.tsx index 2d5106971c..32c5558394 100644 --- a/packages/toolkit/src/query/tests/buildHooks.test.tsx +++ b/packages/toolkit/src/query/tests/buildHooks.test.tsx @@ -873,6 +873,57 @@ describe('hooks tests', () => { } }) + test('Hook subscription failures do not reset isLoading state', async () => { + const states: boolean[] = [] + + function Parent() { + const { isLoading } = api.endpoints.getUserAndForceError.useQuery(1) + + // Collect loading states to verify that it does not revert back to true. + states.push(isLoading) + + // Parent conditionally renders child when loading. + if (isLoading) return null + + return + } + + function Child() { + // Using the same args as the parent + api.endpoints.getUserAndForceError.useQuery(1) + + return null + } + + render(, { wrapper: storeRef.wrapper }) + + // Allow at least three state effects to hit. + // Trying to see if any [true, false, true] occurs. + await act(async () => { + await waitMs(1) + }) + + await act(async () => { + await waitMs(1) + }) + + await act(async () => { + await waitMs(1) + }) + + // Find if at any time the isLoading state has reverted + // E.G.: `[..., true, false, ..., true]` + // ^^^^ ^^^^^ ^^^^ + const firstTrue = states.indexOf(true) + const firstFalse = states.slice(firstTrue).indexOf(false) + const revertedState = states.slice(firstFalse).indexOf(true) + + expect( + revertedState, + `Expected isLoading state to never revert back to true but did after ${revertedState} renders...`, + ).toBe(-1) + }) + describe('Hook middleware requirements', () => { let mock: MockInstance