diff --git a/packages/toolkit/src/query/core/buildThunks.ts b/packages/toolkit/src/query/core/buildThunks.ts index 58496877aa..f55e56549a 100644 --- a/packages/toolkit/src/query/core/buildThunks.ts +++ b/packages/toolkit/src/query/core/buildThunks.ts @@ -8,7 +8,10 @@ import type { import { BaseQueryArg } from '../baseQueryTypes' import type { RootState, QueryKeys, QuerySubstateIdentifier } from './apiState' import { QueryStatus, CombinedState } from './apiState' -import type { StartQueryActionCreatorOptions } from './buildInitiate' +import type { + QueryActionCreatorResult, + StartQueryActionCreatorOptions, +} from './buildInitiate' import type { AssertTagTypes, EndpointDefinition, @@ -430,6 +433,8 @@ In the case of an unhandled error, no tags will be "provided" or "invalidated".` const hasMaxAge = ( options: any ): options is { ifOlderThan: false | number } => 'ifOlderThan' in options + const hasCleanup = (options: any): options is { cleanup?: boolean } => + 'cleanup' in options const prefetch = >( @@ -440,33 +445,42 @@ In the case of an unhandled error, no tags will be "provided" or "invalidated".` (dispatch: ThunkDispatch, getState: () => any) => { const force = hasTheForce(options) && options.force const maxAge = hasMaxAge(options) && options.ifOlderThan + const cleanupSubscription = hasCleanup(options) && options.cleanup const queryAction = (force: boolean = true) => (api.endpoints[endpointName] as ApiEndpointQuery).initiate( arg, { forceRefetch: force } ) + const queryCleanup = ( + result: QueryActionCreatorResult, + doCleanup: boolean = false + ) => { + if (doCleanup) { + result.unwrap().finally(result.unsubscribe) + } + } const latestStateValue = ( api.endpoints[endpointName] as ApiEndpointQuery ).select(arg)(getState()) if (force) { - dispatch(queryAction()) + queryCleanup(dispatch(queryAction()), cleanupSubscription) } else if (maxAge) { const lastFulfilledTs = latestStateValue?.fulfilledTimeStamp if (!lastFulfilledTs) { - dispatch(queryAction()) + queryCleanup(dispatch(queryAction()), cleanupSubscription) return } const shouldRetrigger = (Number(new Date()) - Number(new Date(lastFulfilledTs))) / 1000 >= maxAge if (shouldRetrigger) { - dispatch(queryAction()) + queryCleanup(dispatch(queryAction()), cleanupSubscription) } } else { // If prefetching with no options, just let it try - dispatch(queryAction(false)) + queryCleanup(dispatch(queryAction(false)), cleanupSubscription) } } diff --git a/packages/toolkit/src/query/core/module.ts b/packages/toolkit/src/query/core/module.ts index 91f048a322..42b58efad5 100644 --- a/packages/toolkit/src/query/core/module.ts +++ b/packages/toolkit/src/query/core/module.ts @@ -54,11 +54,14 @@ import { enablePatches } from 'immer' * `force` * - If `force: true`, it will ignore the `ifOlderThan` value if it is set and the query will be run even if it exists in the cache. */ -export type PrefetchOptions = +export type PrefetchOptions = ( | { ifOlderThan?: false | number } | { force?: boolean } +) & { + cleanup?: boolean +} export const coreModuleName = /* @__PURE__ */ Symbol() export type CoreModule =