diff --git a/docs/rtk-query/api/createApi.mdx b/docs/rtk-query/api/createApi.mdx index 6e99e1476e..c3992c76e8 100644 --- a/docs/rtk-query/api/createApi.mdx +++ b/docs/rtk-query/api/createApi.mdx @@ -54,7 +54,7 @@ export const { useGetPokemonByNameQuery } = pokemonApi // highlight-end ``` -## Parameters +## `createApi` Parameters `createApi` accepts a single configuration object parameter with the following options: @@ -357,6 +357,10 @@ See also [Server Side Rendering](../usage/server-side-rendering.mdx) and By default, this function will take the query arguments, sort object keys where applicable, stringify the result, and concatenate it with the endpoint name. This creates a cache key based on the combination of arguments + endpoint name (ignoring object key order), such that calling any given endpoint with the same arguments will result in the same cache key. +### `invalidationBehavior` + +[summary](docblock://query/createApi.ts?token=CreateApiOptions.invalidationBehavior) + ### `keepUnusedDataFor` [summary](docblock://query/createApi.ts?token=CreateApiOptions.keepUnusedDataFor) @@ -389,7 +393,7 @@ You can set this globally in `createApi`, but you can also override the default If you specify `track: false` when manually dispatching queries, RTK Query will not be able to automatically refetch for you. ::: -## Anatomy of an endpoint +## Endpoint Definition Parameters ### `query` diff --git a/packages/toolkit/src/query/react/buildHooks.ts b/packages/toolkit/src/query/react/buildHooks.ts index daec42efe2..63aadd94e1 100644 --- a/packages/toolkit/src/query/react/buildHooks.ts +++ b/packages/toolkit/src/query/react/buildHooks.ts @@ -905,16 +905,17 @@ export function buildHooks({ const { endpointName } = lastResult const endpointDefinition = context.endpointDefinitions[endpointName] if ( + queryArgs !== skipToken && serializeQueryArgs({ queryArgs: lastResult.originalArgs, endpointDefinition, endpointName, }) === - serializeQueryArgs({ - queryArgs, - endpointDefinition, - endpointName, - }) + serializeQueryArgs({ + queryArgs, + endpointDefinition, + endpointName, + }) ) lastResult = undefined } diff --git a/packages/toolkit/src/query/tests/buildHooks.test.tsx b/packages/toolkit/src/query/tests/buildHooks.test.tsx index d17184abb1..e3a0989300 100644 --- a/packages/toolkit/src/query/tests/buildHooks.test.tsx +++ b/packages/toolkit/src/query/tests/buildHooks.test.tsx @@ -3077,6 +3077,48 @@ describe('skip behavior', () => { expect(getSubscriptionCount('getUser(1)')).toBe(0) }) + test('skipToken does not break serializeQueryArgs', async () => { + const { result, rerender } = renderHook( + ([arg, options]: Parameters< + typeof api.endpoints.queryWithDeepArg.useQuery + >) => api.endpoints.queryWithDeepArg.useQuery(arg, options), + { + wrapper: storeRef.wrapper, + initialProps: [skipToken], + }, + ) + + expect(result.current).toEqual(uninitialized) + await waitMs(1) + + expect(getSubscriptionCount('nestedValue')).toBe(0) + // also no subscription on `getUser(skipToken)` or similar: + expect(getSubscriptions()).toEqual({}) + + rerender([{ param: { nested: 'nestedValue' } }]) + + await act(async () => { + await waitForFakeTimer(150) + }) + + expect(result.current).toMatchObject({ status: QueryStatus.fulfilled }) + await waitMs(1) + + expect(getSubscriptionCount('nestedValue')).toBe(1) + expect(getSubscriptions()).not.toEqual({}) + + rerender([skipToken]) + + expect(result.current).toEqual({ + ...uninitialized, + isSuccess: true, + currentData: undefined, + data: {}, + }) + await waitMs(1) + expect(getSubscriptionCount('nestedValue')).toBe(0) + }) + test('skipping a previously fetched query retains the existing value as `data`, but clears `currentData`', async () => { const { result, rerender } = renderHook( ([arg, options]: Parameters) =>