Endpoint name usage
When defining a key like getPosts in endpoints, this name becomes exportable from api and can be referenced under api.endpoints.getPosts.useQuery(), api.endpoints.getPosts.initiate() and api.endpoints.getPosts.select(). For mutations, use useMutation() instead of useQuery().
endpoints parameter and QueryDefinition structure
The endpoints parameter is a function that receives an EndpointBuilder and returns an object of endpoint definitions. Query endpoint definitions (build.query()) are used to cache data fetched from the server and must specify either a query field or a queryFn function. Mutation endpoint definitions (build.mutation()) are used to send updates to the server and force invalidation and refetching of query endpoints.
query function signature
The query function signature is (arg: QueryArg) => string | Record<string, unknown>. With fetchBaseQuery, it can return string | FetchArgs. The query function returns the arguments to pass to the baseQuery function.
queryFn function signature
queryFn(arg: QueryArg, api: BaseQueryApi, extraOptions: BaseQueryExtraOptions<BaseQuery>, baseQuery: (arg: Parameters<BaseQuery>[0]) => ReturnType<BaseQuery>): MaybePromise<{error: BaseQueryError<BaseQuery>, data?: undefined} | {error?: undefined, data: ResultType}>. It is called with the same arguments as baseQuery and is expected to return an object with either a data or error property, or a promise that resolves to such an object.
transformResponse usage
transformResponse(response, meta, arg) => ResultType | Promise<ResultType> allows you to manipulate the data returned from a query before it is put in the cache. It is only available with query endpoints, not queryFn. For example: transformResponse: (response, meta, arg) => response.some.deeply.nested.collection
transformErrorResponse usage
transformErrorResponse(response, meta, arg) => unknown allows you to manipulate the error returned from a query before it is put in the cache. It is only available with query endpoints, not queryFn. For example: transformErrorResponse: (response, meta, arg) => response.data.some.deeply.nested.errorObject
queryFn function arguments details
queryFn receives: args (the argument provided when the query itself is called), api (BaseQueryApi object with signal, dispatch, and getState properties), extraOptions (optional extraOptions provided for the endpoint), and baseQuery (the baseQuery function provided to the api itself). signal is an AbortSignal for aborting requests, dispatch is store.dispatch, and getState accesses current store state.
injectEndpoints primary use cases
injectEndpoints is primarily useful for code splitting and hot reloading. It allows endpoint definitions to be injected at runtime after the initial API slice has been defined, which is beneficial for apps with many endpoints.
injectEndpoints function signature and parameters
injectEndpoints accepts an InjectedEndpointOptions object with the following properties: endpoints (required) - a builder callback that returns NewEndpointDefinitions, matching the same signature as createApi.endpoints; overrideExisting (optional) - a boolean or 'throw' string controlling whether endpoints are overridden if redefined. If true, overrides existing endpoints with the new definition. If 'throw', throws an error if an endpoint is redefined with a different definition. If false or unset (default), does not override existing endpoints and logs a warning in development.
injectEndpoints return value and behavior
injectEndpoints returns an EnhancedApiSlice containing the combined endpoint definitions merged from the existing API slice and the new endpoint definitions using a shallow merge. Endpoints will not be overridden unless overrideExisting is set to true. If a name clash occurs and overrideExisting is not true, a development mode warning is shown.
enhanceEndpoints endpoint definition syntax - object and function forms
In the endpoints property of enhanceEndpoints, each endpoint can be defined as a plain object with partial properties (e.g., { providesTags: ['User'] }) or as a function that receives the endpoint definition as an argument and modifies it directly.
enhanceEndpoints function signature and parameters
enhanceEndpoints accepts an EnhanceEndpointsOptions object with the following properties: addTagTypes (optional) - a readonly array of strings for tag types to add; endpoints (optional) - a record mapping endpoint names to Partial<EndpointDefinition> objects.
enhanceEndpoints return value and merging behavior
enhanceEndpoints returns an EnhancedApiSlice containing the combined endpoint definitions. Unlike injectEndpoints, the partial endpoint definitions are merged together on a per-definition basis using Object.assign(existingEndpoint, newPartialEndpoint) rather than replacing existing definitions.
skipToken symbol disables query selectors
RTKQ defines a Symbol named skipToken. Passing skipToken as the query argument to a selector returns a default uninitialized state, which can be used to avoid returning a value if a query is supposed to be disabled.
select memoization pitfall
Each call to .select(someCacheKey) returns a new selector function instance. For memoization to work correctly, create a selector function once per cache key and reuse that instance, rather than creating a new selector instance each time.
select query example with useMemo
Example of query selection: const selectPost = useMemo(() => api.endpoints.getPost.select(postId), [postId]); const { data, isLoading } = useAppSelector(selectPost). Use useMemo to ensure .select() is only called when the cache key changes.
select mutation example with skipToken
Example of mutation selection: const [requestId, setRequestId] = useState<typeof skipToken | string>(skipToken); const selectMutationResult = useMemo(() => api.endpoints.addPost.select(requestId), [requestId]); const { isLoading } = useAppSelector(selectMutationResult). Initialize requestId with skipToken and update it after dispatching the mutation.
Matchers for endpoint actions
Each endpoint has three matchers: matchPending, matchFulfilled, and matchRejected. These are Redux Toolkit action matching utilities implemented as isAllOf(isPending/isFulfilled/isRejected(thunk), matchesEndpoint(endpoint)). They can be used in createSlice.extraReducers or custom middleware.
Manual subscription management with initiate
When using initiate outside of React hooks, you must store a reference to the returned promise and manually unsubscribe when the component unmounts. The returned result has an unsubscribe callback.
initiate thunk action creator signature for queries
For query endpoints, StartQueryActionCreator accepts an arg of any type and optional StartQueryActionCreatorOptions, returning a ThunkAction<QueryActionCreatorResult, any, any, UnknownAction>.
EndpointLogic structure
Each endpoint in an API slice contains the following fields: initiate (InitiateRequestThunk), select (CreateCacheSelectorFactory), matchPending (Matcher<PendingAction>), matchFulfilled (Matcher<FulfilledAction>), and matchRejected (Matcher<RejectedAction>).
initiate thunk action creator signature for mutations
For mutation endpoints, StartMutationActionCreator accepts an arg of any type and optional StartMutationActionCreatorOptions, returning a ThunkAction<MutationActionCreatorResult<D>, any, any, UnknownAction>.
StartQueryActionCreatorOptions interface
StartQueryActionCreatorOptions has three optional fields: subscribe (boolean), forceRefetch (boolean | number), and subscriptionOptions (SubscriptionOptions object).
StartMutationActionCreatorOptions interface
StartMutationActionCreatorOptions has one optional field: track (boolean, defaults to true). When track is false, the mutation is not tracked in the store and state/errors are not held in store.
SubscriptionOptions for polling and refetching
SubscriptionOptions contains: pollingInterval (number in milliseconds, defaults to 0 for off), refetchOnReconnect (boolean, defaults to false, requires setupListeners, not evaluated if skip is true), and refetchOnFocus (boolean, defaults to false, requires setupListeners, not evaluated if skip is true).
initiate action creator is a Redux thunk
The initiate field is a Redux thunk action creator that triggers data fetch queries or mutations. React hooks users typically do not need to use these directly as hooks automatically dispatch these actions.
initiate query example using dispatch
Example of manual query subscription: const result = dispatch(api.endpoints.getPost.initiate(postId)); return result.unsubscribe; // call in useEffect cleanup. This adds a subscription and returns an unsubscribe callback.
initiate mutation with track option
Example mutation dispatch with track false: dispatch(api.endpoints.addPost.initiate(newPost), { track: false }). Use track: false when not interested in the mutation result being stored in state.
select selector factory signature for queries
QueryResultSelectorFactory accepts a queryArg (QueryArg | SkipToken) and returns a function that takes RootState and returns QueryResultSelectorResult<Definition>.
select selector factory signature for mutations
MutationResultSelectorFactory accepts a requestId (string | SkipToken) and returns a function that takes RootState and returns MutationSubState<Definition> & RequestStatusFlags.
select creates memoized selector using Reselect
The select function creates a memoized selector using Reselect's createSelector for reading cached data using a given cache key.
injectEndpoints allows runtime endpoint injection
Each API slice allows additional endpoint definitions to be injected at runtime after the initial API slice has been defined. This is beneficial for apps with many endpoints and is useful for code-splitting endpoint definitions across multiple files while maintaining a single API slice.
enhanceEndpoints allows endpoint configuration modification
The enhanceEndpoints function allows you to modify the configuration of endpoint definitions after they have been created, primarily useful for adding custom behavior to automatically-generated endpoint definitions from API schema files.
endpoints field maps to Redux logic
The endpoints field in the API slice object maps endpoint names provided to createApi to the core Redux logic (thunks and selectors) used to trigger data fetches and read cached data. When using React-specific createApi, each endpoint definition also contains auto-generated React hooks.
RTK Query API definition style
RTK Query uses declarative API definition where endpoints are defined upfront in an API slice.
Typing query and mutation endpoints with ResultType and QueryArg
Endpoints are typed using generics in the format <ResultType, QueryArg>:
- ResultType: the type of final data returned by the query, factoring in optional transformResponse. If transformResponse is provided, input type for transformResponse must be specified to indicate what the initial query returns, and transformResponse return type must match ResultType. If using queryFn instead of query, it must return {data: ResultType} for success case.
- QueryArg: type of input passed as parameter to query property or first parameter of queryFn. If query has no parameter, provide void type explicitly. If query has optional parameter, use union type with the parameter type and void, e.g. number | void.
Example: defining endpoints with TypeScript
import { createApi, fetchBaseQuery } from '@reduxjs/toolkit/query/react'
interface Post {
id: number
name: string
}
const api = createApi({
baseQuery: fetchBaseQuery({ baseUrl: '/' }),
endpoints: (build) => ({
getPost: build.query<Post, number>({
query: (id) => `post/${id}`,
transformResponse: (rawResult: { result: { post: Post } }, meta) => {
return rawResult.result.post
},
}),
}),
})
This example shows ResultType as Post and QueryArg as number, with transformResponse receiving the raw result type and optional meta parameter.
queryFn receives type from endpoint generics
A queryFn will receive its result and arg types from the generics provided to the corresponding built endpoint. The queryFn receives (arg, queryApi, extraOptions, baseQuery) as parameters where arg is typed as QueryArg from the endpoint definition.
Example: queryFn error handling with fetchBaseQuery
import { createApi, fetchBaseQuery } from '@reduxjs/toolkit/query/react'
interface Post {
id: number
name: string
}
const api = createApi({
baseQuery: fetchBaseQuery({ baseUrl: '/' }),
endpoints: (build) => ({
getPost: build.query<Post, number>({
queryFn: (arg, queryApi, extraOptions, baseQuery) => {
if (arg <= 0) {
return {
error: {
status: 500,
statusText: 'Internal Server Error',
data: 'Invalid ID provided.',
},
}
}
const post: Post = {
id: arg,
name: 'example',
}
return { data: post }
},
}),
}),
})
This shows returning a properly typed error from queryFn with fetchBaseQuery error shape.
transformResponse endpoint option to modify cached data shape
The transformResponse endpoint option allows you to modify the fetched data so it is stored in a different shape, such as using createEntityAdapter to normalize the data for a specific response before it is inserted into the cache.