RTK Query is a caching data-fetching layer built into Redux Toolkit 3,824 , imported from @reduxjs/toolkit/query/react. You describe endpoints once; it generates a slice, a middleware and a Hook per endpoint, and handles deduplication, caching, loading flags, refetching and invalidation — replacing everything you would otherwise hand-write for server data.
import { createApi, fetchBaseQuery } from '@reduxjs/toolkit/query/react';
export const catalogApi = createApi({
reducerPath: 'catalogApi', // where the cache lives
baseQuery: fetchBaseQuery({ baseUrl: 'https://api.example.com/' }),
tagTypes: ['Product'],
endpoints: (build) => ({
getProducts: build.query({
query: (page = 1) => `products?page=${page}`, // the argument is the key
providesTags: (result = []) => result.map(p => ({ type: 'Product', id: p.id })),
}),
}),
});
export const { useGetProductsQuery } = catalogApi; // generated, one per endpoint
export const store = configureStore({
reducer: { [catalogApi.reducerPath]: catalogApi.reducer },
middleware: (g) => g().concat(catalogApi.middleware), // required: drives the cache
});
function Products({ page }) {
const { data, error, isLoading, isFetching } = useGetProductsQuery(page);
if (isLoading) return <p>Loading...</p>; // first load for this hook
if (error) return <p role="alert">Request failed</p>;
return <ul style={{ opacity: isFetching ? 0.5 : 1 }}> {/* background refetch */}
{data.map(p => <li key={p.id}>{p.name}</li>)}</ul>;
}Two flags, two meanings. isLoading is true only while there is no data at all for this Hook; isFetching is true whenever a request is in flight, including the refetch after a page change. Dimming the old page instead of replacing it with a spinner is what makes pagination feel instant.
The cache is keyed by endpoint plus serialized argument, so two components calling useGetProductsQuery(1) share one request and one entry, while 2 starts a second entry. A query can be held back with { skip: !id }, deferred with useLazyGetProductsQuery(), or narrowed with selectFromResult so the component re-renders only when the part it displays changes.