diff --git a/packages/query-core/src/queryClient.ts b/packages/query-core/src/queryClient.ts index 62aebf93a6..15df263919 100644 --- a/packages/query-core/src/queryClient.ts +++ b/packages/query-core/src/queryClient.ts @@ -62,6 +62,7 @@ export class QueryClient { private defaultOptions: DefaultOptions private queryDefaults: QueryDefaults[] private mutationDefaults: MutationDefaults[] + private mountCount: number private unsubscribeFocus?: () => void private unsubscribeOnline?: () => void @@ -72,6 +73,7 @@ export class QueryClient { this.defaultOptions = config.defaultOptions || {} this.queryDefaults = [] this.mutationDefaults = [] + this.mountCount = 0 if (process.env.NODE_ENV !== 'production' && config.logger) { this.logger.error( @@ -81,6 +83,9 @@ export class QueryClient { } mount(): void { + this.mountCount++ + if (this.mountCount !== 1) return + this.unsubscribeFocus = focusManager.subscribe(() => { if (focusManager.isFocused()) { this.resumePausedMutations() @@ -96,8 +101,14 @@ export class QueryClient { } unmount(): void { + this.mountCount-- + if (this.mountCount !== 0) return + this.unsubscribeFocus?.() + this.unsubscribeFocus = undefined + this.unsubscribeOnline?.() + this.unsubscribeOnline = undefined } isFetching(filters?: QueryFilters): number diff --git a/packages/query-core/src/tests/queryClient.test.tsx b/packages/query-core/src/tests/queryClient.test.tsx index 8a91ef4632..a8b5533b09 100644 --- a/packages/query-core/src/tests/queryClient.test.tsx +++ b/packages/query-core/src/tests/queryClient.test.tsx @@ -23,6 +23,7 @@ describe('queryClient', () => { afterEach(() => { queryClient.clear() + queryClient.unmount() }) describe('defaultOptions', () => { @@ -1466,6 +1467,75 @@ describe('queryClient', () => { mutationCacheResumePausedMutationsSpy.mockRestore() onlineManager.setOnline(undefined) }) + + test('should notify queryCache and mutationCache after multiple mounts and single unmount', async () => { + const testClient = createQueryClient() + testClient.mount() + testClient.mount() + testClient.unmount() + + const queryCacheOnFocusSpy = jest.spyOn( + testClient.getQueryCache(), + 'onFocus', + ) + const queryCacheOnOnlineSpy = jest.spyOn( + testClient.getQueryCache(), + 'onOnline', + ) + const mutationCacheResumePausedMutationsSpy = jest.spyOn( + testClient.getMutationCache(), + 'resumePausedMutations', + ) + + onlineManager.setOnline(true) + expect(queryCacheOnOnlineSpy).toHaveBeenCalledTimes(1) + expect(mutationCacheResumePausedMutationsSpy).toHaveBeenCalledTimes(1) + + focusManager.setFocused(true) + expect(queryCacheOnFocusSpy).toHaveBeenCalledTimes(1) + expect(mutationCacheResumePausedMutationsSpy).toHaveBeenCalledTimes(2) + + queryCacheOnFocusSpy.mockRestore() + queryCacheOnOnlineSpy.mockRestore() + mutationCacheResumePausedMutationsSpy.mockRestore() + focusManager.setFocused(undefined) + onlineManager.setOnline(undefined) + }) + + test('should not notify queryCache and mutationCache after multiple mounts/unmounts', async () => { + const testClient = createQueryClient() + testClient.mount() + testClient.mount() + testClient.unmount() + testClient.unmount() + + const queryCacheOnFocusSpy = jest.spyOn( + testClient.getQueryCache(), + 'onFocus', + ) + const queryCacheOnOnlineSpy = jest.spyOn( + testClient.getQueryCache(), + 'onOnline', + ) + const mutationCacheResumePausedMutationsSpy = jest.spyOn( + testClient.getMutationCache(), + 'resumePausedMutations', + ) + + onlineManager.setOnline(true) + expect(queryCacheOnOnlineSpy).not.toHaveBeenCalled() + expect(mutationCacheResumePausedMutationsSpy).not.toHaveBeenCalled() + + focusManager.setFocused(true) + expect(queryCacheOnFocusSpy).not.toHaveBeenCalled() + expect(mutationCacheResumePausedMutationsSpy).not.toHaveBeenCalled() + + queryCacheOnFocusSpy.mockRestore() + queryCacheOnOnlineSpy.mockRestore() + mutationCacheResumePausedMutationsSpy.mockRestore() + focusManager.setFocused(undefined) + onlineManager.setOnline(undefined) + }) }) describe('setMutationDefaults', () => {