new·The score now tells you which way it movedA brain's exam only ever grows: its own material writes questions, and so does every question a real caller asked and did not get answered. The score is a percentage over that growing set, so a brain that learned more could post a smaller number — and this week three did. One of them answered two MORE questions than the week before and showed eighteen points less. Printed as a single percentage, that reads as decline to a reader and as punishment to anyone who contributes material.all news →
mozg.beta
Sign in

Redux Toolkit · RTK Query · all subjects

createapi/endpoints/query

61 notes in this subject, read out of this brain and free to use. This is page 1 of 2.

Query endpoint definition fields

Query endpoints can have: query(arg) function (required if no queryFn), queryFn(arg, api, extraOptions, baseQuery) function (required if no query), transformResponse(baseQueryReturnValue, meta, arg) (optional, not with queryFn), transformErrorResponse(baseQueryReturnValue, meta, arg) (optional, not with queryFn), extraOptions (optional), providesTags (optional), keepUnusedDataFor (optional), onQueryStarted (optional), onCacheEntryAdded (optional), argSchema (optional), rawResponseSchema (optional, not with queryFn), responseSchema (optional), rawErrorResponseSchema (optional, not with queryFn), errorResponseSchema (optional), metaSchema (optional).

forceRefetch parameter for query endpoints

forceRefetch is an optional parameter for query endpoints only. It is a function with signature (params: {currentArg, previousArg, state, endpointState}) => boolean that determines whether a query should be refetched based on comparing current and previous arguments.

merge parameter for query endpoints

merge is an optional parameter for query endpoints only that allows customizing how paginated or accumulated data is merged into the cache.

serializeQueryArgs per-endpoint override

serializeQueryArgs is an optional parameter for query endpoints only that allows overriding the api-wide serializeQueryArgs function for a specific endpoint.

useQuery hook signature and parameters

useQuery accepts two parameters: arg (the query argument used to construct the query and as a cache key, or skipToken to skip) and options (UseQueryOptions controlling fetching behavior). UseQueryOptions include pollingInterval, skipPollingIfUnfocused, refetchOnReconnect, refetchOnFocus, skip, refetchOnMountOrArgChange, and selectFromResult. useQuery returns a UseQueryResult object.

useQuery return object properties

UseQueryResult<T> contains: originalArgs (arguments passed to query), data (latest result regardless of hook arg), currentData (latest result for current hook arg), error (error result if present), requestId (string generated by RTK Query), endpointName (name of endpoint), startedTimeStamp (when query was initiated), fulfilledTimeStamp (when query was completed), isUninitialized (query has not started), isLoading (query loading for first time, no data yet), isFetching (query fetching but might have earlier data), isSuccess (query has successful data), isError (query in error state), and refetch (function to force refetch returning QueryActionCreatorResult).

useLazyQuery hook signature and parameters

useLazyQuery accepts optional UseLazyQueryOptions: pollingInterval, skipPollingIfUnfocused, refetchOnReconnect, refetchOnFocus, and selectFromResult. Returns a tuple containing trigger function, result object, and lastPromiseInfo object.

useLazyQuery trigger function signature

useLazyQuery trigger function accepts arg (any) and preferCacheValue (boolean, optional) and returns a Promise<QueryResultSelectorResult>. The Promise has properties: arg (whatever argument was provided), requestId (string generated by RTK Query), subscriptionOptions (values used for query subscription), abort (cancel query promise), unwrap (unwrap call and provide raw response/error), unsubscribe (manually unsubscribe from query results), refetch (re-run query), and updateSubscriptionOptions (update subscription options like pollingInterval).

useLazyQuery returns tuple structure

useLazyQuery returns a tuple [trigger, result, lastPromiseInfo]: trigger is a function that fetches data when called, result is a query result object containing loading state and metadata, and lastPromiseInfo is an object containing lastArg (the last argument used to call trigger).

useQueryState hook signature and parameters

useQueryState accepts arg (query argument or skipToken) and optional UseQueryStateOptions: skip (boolean) and selectFromResult (callback). Returns UseQueryStateResult object containing query state without automatic triggering or subscription.

useQuerySubscription hook signature and parameters

useQuerySubscription accepts arg (query argument or skipToken) and optional UseQuerySubscriptionOptions: skip, refetchOnMountOrArgChange, pollingInterval, skipPollingIfUnfocused, refetchOnReconnect, refetchOnFocus. Returns object with refetch method to force query refetch. Subscribes component to keep cached data in store without returning full query state.

useLazyQuerySubscription hook signature and parameters

useLazyQuerySubscription accepts optional UseLazyQuerySubscriptionOptions: pollingInterval, skipPollingIfUnfocused, refetchOnReconnect, refetchOnFocus. Returns tuple [trigger, lastArg]: trigger is function accepting arg and preferCacheValue that fetches data when called, lastArg is the last argument used to call trigger. Options only take effect after lazy query triggered at least once.

skipToken for skipping queries with TypeScript

skipToken can be passed as the arg parameter to useQuery or similar hooks as an alternative way of skipping the query. This provides a type-safe way to skip queries in TypeScript.

RTK Query supports parallel queries

RTK Query supports parallel queries, allowing multiple independent queries to be executed simultaneously.

RTK Query supports dependent queries

RTK Query supports dependent queries, allowing one query to depend on the result of another query.

RTK Query supports skip queries

RTK Query supports skip queries, allowing queries to be conditionally disabled based on their arguments or application state.

RTK Query supports lagged queries

RTK Query supports lagged queries, which keep serving old data while fetching new data.

skipToken for type-safe conditional query skipping

RTK Query provides skipToken export that can be used as an alternative to the skip option for type-safe query skipping. When skipToken is passed as the query argument to useQuery, useQueryState, or useQuerySubscription, it provides the same effect as setting skip: true while being a valid argument in scenarios where arg might be undefined otherwise.

Example: using skipToken for conditional queries

import { skipToken } from '@reduxjs/toolkit/query/react' import { useGetPostQuery } from './api' function MaybePost({ id }: { id?: number }) { // When id is nullish, query is skipped // TypeScript is satisfied that query is only called with number const { data } = useGetPostQuery(id ?? skipToken) return <div>...</div> } This shows using id ?? skipToken to skip query when id is undefined while remaining type-safe.

skip parameter prevents automatic fetching

Query hooks automatically begin fetching data as soon as the component is mounted. The skip parameter in a hook prevents a query from automatically running when you want to delay fetching data until some condition becomes true.

skipToken alternative for TypeScript query skipping

TypeScript users can use skipToken as an alternative to the skip option to skip running a query while still keeping types for the endpoint accurate.

Query error property in hook return

When using fetchBaseQuery, if a query throws an error, it will be returned in the error property of the respective hook. The component will re-render when the error occurs.

Query error example displaying status and data

This example shows how to display query errors in a component. It uses useGetPostsQuery hook, destructures error from the return, and displays error.status and JSON stringified error.data.

streaming data with no initial request using queryFn

A queryFn can populate cache with initial data (e.g., empty array) while streaming updates fill it via onCacheEntryAdded: streamMessages: build.query<Message[], void>({ queryFn: () => ({ data: [] }), async onCacheEntryAdded(arg, { updateCachedData, cacheEntryRemoved }) { const ws = new WebSocket('ws://localhost:8080') ws.addEventListener('message', (event) => { updateCachedData((draft) => { draft.push(JSON.parse(event.data)) }) }) await cacheEntryRemoved ws.close() }, })

transformErrorResponse endpoint option

Individual endpoints accept a transformErrorResponse property that allows manipulation of error responses from a failed baseQuery before the error hits the cache. transformErrorResponse is called with three arguments: the error returned by baseQuery, the meta property from baseQuery (if any), and the arg provided to the endpoint. The return value of transformErrorResponse is used as the cached error. By default, the error payload from the server is returned directly.

queryFn endpoint option

Individual endpoints can accept a queryFn property instead of using baseQuery. A queryFn is an inline baseQuery that receives four arguments: args, api { signal, dispatch, getState }, extraOptions, and baseQuery (the function itself). It must return an object with either a data or error property, similar to baseQuery. queryFn is useful for one-off queries with different behavior, third-party SDK integration, or async tasks that aren't typical request/response.

queryFn use cases

queryFn is useful for: one-off queries with different base URLs or request handling; different error handling behavior per endpoint; requests using third-party library SDKs like Firebase or Supabase; async tasks that are not typical request/response sequences; performing multiple requests within a single query; leveraging invalidation behavior with no relevant query; using streaming updates with no initial request.

transformResponse example unpacking nested data

Example transformResponse for unpacking deeply nested GraphQL data: transformResponse: (response: { posts: { data: Post[] } }) => response.posts.data This extracts the data array from nested response structure before caching.

normalizing response data with createEntityAdapter

transformResponse can normalize array responses using createEntityAdapter. For response [{ id: 1, name: 'Harry' }, { id: 2, name: 'Ron' }], createEntityAdapter normalizes to { ids: [1, 2], entities: { 1: { id: 1, name: 'Harry' }, 2: { id: 2, name: 'Ron' } } }. Example: const postsAdapter = createEntityAdapter<Post>({ sortComparer: (a, b) => a.name.localeCompare(b.name) }) transformResponse(response: Post[]) { return postsAdapter.addMany(postsAdapter.getInitialState(), response) }

queryFn with third-party SDK

Example queryFn using Supabase SDK: queryFn: async () => { const { data, error } = await supabase.from('blogs').select() if (error) { return { error } } return { data } } SDKs like Firebase and Supabase already return { data, error } format, fitting naturally into queryFn.

performing multiple requests in a single queryFn

Example queryFn performing two sequential requests: getRandomUserPosts: build.query<Post, void>({ async queryFn(_arg, _queryApi, _extraOptions, fetchWithBQ) { const randomResult = await fetchWithBQ('users/random') if (randomResult.error) return { error: randomResult.error as FetchBaseQueryError } const user = randomResult.data as User const result = await fetchWithBQ(`user/${user.id}/posts`) return result.data ? { data: result.data as Post } : { error: result.error as FetchBaseQueryError } }, }) The fourth queryFn argument is fetchWithBQ (the baseQuery function itself) for chaining requests.

createApi with fetchBaseQuery minimal query endpoint example

This example shows how to define a basic query endpoint with RTK Query that fetches Pokemon data: ```ts import { createApi, fetchBaseQuery } from '@reduxjs/toolkit/query/react' import type { Pokemon } from './types' export const api = createApi({ baseQuery: fetchBaseQuery({ baseUrl: 'https://pokeapi.co/api/v2/' }), reducerPath: 'pokemonApi', endpoints: (build) => ({ getPokemonByName: build.query<Pokemon, string>({ query: (name) => `pokemon/${name}`, }), }), }) export const { useGetPokemonByNameQuery } = api ``` The endpoint uses the name parameter to construct the query path, returning a Pokemon type. The auto-generated useGetPokemonByNameQuery hook is exported for use in components.

RTK Query does not include built-in pagination behavior

RTK Query does not include any built-in pagination behavior. However, RTK Query makes it straightforward to integrate with a standard index-based pagination API, which is the most common form of pagination.

Paginated query endpoint with page argument

To set up a paginated endpoint, create a query endpoint that accepts a page number argument. The page argument can be a number or void, with a default value. Example: build.query<ListResponse<Post>, number | void>({ query: (page = 1) => `posts?page=${page}` })

ListResponse interface for paginated API responses

A typical paginated API response includes page (number), per_page (number), total (number), total_pages (number), and data (array of results). Example: interface ListResponse<T> { page: number; per_page: number; total: number; total_pages: number; data: T[] }

Triggering pagination with state variable

To navigate between pages, use a state variable to track the current page number and pass it to the query hook. Incrementing or decrementing the page variable will trigger a new query for that page. Example: const [page, setPage] = useState(1); const { data: posts } = useListPostsQuery(page)

Transformed response shape with EntityAdapter

EntityAdapter transforms a Message array from format [{ id: 0, channel: 'redux', userName: 'Mark', text: 'Welcome to #redux!' }, ...] into EntityState format with structure { ids: [0, 1], entities: { 0: { id: 0, channel: 'redux', userName: 'Mark', text: 'Welcome to #redux!' }, 1: {...} } }.

transformResponse callback signature and purpose

transformResponse is a callback with signature (response: ResponseType, meta, arg) that picks out data from the response and prevents nested properties in a hook or selector before caching.

transformErrorResponse callback signature and purpose

transformErrorResponse is a callback with signature (response: { status: string | number }, meta, arg) that picks out errors from the response and prevents nested properties in a hook or selector.

Query hook generation: endpoint name to hook name

Hooks are automatically generated based on the endpoint name in the service definition. An endpoint field with getPost: build.query() generates a hook named useGetPostQuery, and also generates a generically-named hook attached to the endpoint like api.endpoints.getPost.useQuery.

Five query-related hooks in RTK Query

RTK Query provides five query-related hooks: (1) useQuery - composes useQuerySubscription and useQueryState, automatically triggers fetches and subscriptions, (2) useQuerySubscription - returns refetch function, automatically triggers fetches and subscriptions, (3) useQueryState - returns query state for given skip and selectFromResult, (4) useLazyQuery - returns tuple with trigger function and result, manual control over fetching with preferCacheValue option, (5) useLazyQuerySubscription - returns tuple with trigger function, manual control over fetching with preferCacheValue option.

Query hook parameters: queryArg and queryOptions

Query hooks expect two parameters: (queryArg?, queryOptions?). The queryArg param is passed through to the underlying query callback to generate the URL. The queryOptions object controls data fetching behavior.

Query hook options: skip, pollingInterval, selectFromResult

Query hook options include: skip (allows a query to skip running for that render, defaults to false), pollingInterval (allows a query to automatically refetch on a provided interval in milliseconds, defaults to 0 meaning off), selectFromResult (allows altering the returned value of the hook to obtain a subset of the result, render-optimized for the returned subset).

Query hook return value: data property

The data property in a query hook return object contains the latest returned result regardless of hook arg, if present.

Query hook return value: currentData property

The currentData property in a query hook return object contains the latest returned result for the current hook arg, if present. This allows showing data only corresponding to the current argument.

Query hook return value: error, isUninitialized, isLoading

Query hook return values include: error (the error result if present), isUninitialized (when true indicates the query has not started yet), isLoading (when true indicates the query is currently loading for the first time and has no data yet; true for the first request but not subsequent requests).

Query hook return value: isFetching, isSuccess, isError, refetch

Query hook return values include: isFetching (when true indicates the query is currently fetching but might have data from an earlier request; true for both first and subsequent requests), isSuccess (when true indicates the query has data from a successful request), isError (when true indicates the query is in an error state), refetch (a function to force refetch the query).

isLoading vs isFetching distinction

isLoading refers to a query being in flight for the first time for the given hook with no data available. isFetching refers to a query being in flight for the given endpoint and query param combination but not necessarily for the first time, and data may be available from an earlier request. This distinction allows greater control when handling UI behavior: isLoading can display a skeleton while loading for the first time, while isFetching can grey out old data when changing query params or when data is invalidated and re-fetched.

selectFromResult for extracting single results from collection

selectFromResult allows getting a specific segment from a query result in a performant manner. When using this feature, the component will not rerender unless the underlying data of the selected item has changed. If the selected item is one element in a larger collection, it will disregard changes to elements in the same collection.

selectFromResult equality check for rerenders

A shallow equality check is performed on the overall return value of selectFromResult to determine whether to force a rerender. If a new array/object is created and used as a return value within the callback, it will hinder performance benefits by being identified as a new item each time the callback runs. To avoid re-creating empty arrays/objects each time, declare them outside of the component to maintain a stable reference.

Example: Query endpoint with full options

Example showing a query endpoint with build.query<Post, number>() accepting a number id, using query callback to construct URL, transformResponse to extract response.data, transformErrorResponse to extract response.status, providesTags for cache invalidation, and lifecycle callbacks onQueryStarted and onCacheEntryAdded.

Example: useQuery hook usage with options

Example showing useGetPostQuery(id) with options: pollingInterval: 3000 (refetch every 3 seconds), refetchOnMountOrArgChange: true (always refetch on mount), skip: false (do not skip the query). Component checks isLoading to show loading state, checks for post data, and uses isFetching to show refetching indicator.

Example: selectFromResult to extract single item from collection

Example showing api.useGetPostsQuery(undefined, { selectFromResult: ({ data }) => ({ post: data?.find((post) => post.id === id) }) }) to select a single post from the collection result, only rerendering if that specific post's data changes.

Example: selectFromResult with stable empty array

Example showing declaration of const emptyArray: Post[] = [] outside the component, then used in selectFromResult to return posts: data ?? emptyArray. This prevents unnecessary rerenders by maintaining a stable reference to the empty array rather than re-creating it on each callback run.

Example: Using currentData for per-argument rendering

Example showing useGetPostsByUserQuery(userName) with currentData, isFetching, isError. When isError returns error message, when isFetching && !currentData shows skeleton, otherwise renders currentData and greys out with className when isFetching. This ensures skeleton is shown when user changes rather than greying out old user's data.

Accessing refetch without React Hooks

If not using React Hooks, refetch can be accessed by dispatching initiate: const { status, data, error, refetch } = dispatch(pokemonApi.endpoints.getPokemon.initiate('bulbasaur'))

Query definition: fetch data and cache on client

Queries are operations that fetch data from the server and cache it within the client. This is the most common use case for RTK Query. Queries should only be used for requests that retrieve data; mutations should be used for anything that alters data on the server or will possibly invalidate the cache.

Query endpoint definition with build.query()

Query endpoints are defined by returning an object inside the endpoints section of createApi and defining fields using the build.query() method. Query endpoints should define either a query callback that constructs the URL (including any URL query params), or a queryFn callback that may do arbitrary async logic and return a result.

Query callback single argument for URL generation

If the query callback needs additional data to generate the URL, it should be written to take a single argument. If multiple parameters are needed, they should be passed formatted as a single options object.

Query endpoint capabilities: response transform, tags, lifecycle

Query endpoints may modify the response contents before the result is cached using transformResponse, define tags to identify cache invalidation using providesTags, and provide cache entry lifecycle callbacks (onQueryStarted, onCacheEntryAdded) to run additional logic as cache entries are added and removed.

Give your agent this brain