Suggest an editImprove this articleRefine the answer for “How does RTK Query cache data?”. Your changes go to moderation before they’re published.Approval requiredContentWhat you’re changing🇺🇸EN🇺🇦UAPreviewTitle (EN)Short answer (EN)**RTK Query** is a layer on top of Redux Toolkit that makes network requests, caches responses in the Redux store, and updates the UI from the cache without repeated requests. React components don't know about the requests directly - they just subscribe to "data", and RTK Query itself decides whether to take it from the cache or from the server. **Key point:** RTK Query caches data by a unique query key (`endpoint + arguments`), stores it in the Redux store, and automatically invalidates it via `providesTags` / `invalidatesTags`.Shown above the full answer for quick recall.Answer (EN)Image## 1. What RTK Query does overall RTK Query is a layer on top of Redux Toolkit that: - makes network requests (fetch/axios, etc.); - caches responses; - updates the UI from the cache without repeated requests; - automatically refetches data when needed. The idea: > React components **don't know about requests directly** - they just subscribe to "data", > and RTK Query itself decides whether to take it from the cache or from the server. --- ## 2. How the cache is structured internally RTK Query stores cached data **in the Redux store** inside its own "slice", created via `createApi()`. ```javascript const api = createApi({ reducerPath: 'api', baseQuery: fetchBaseQuery({ baseUrl: '/api' }), endpoints: builder => ({ getUser: builder.query<User, string>({ query: (id) => `/user/${id}`, }), }), }); ``` After calling: ```javascript const { data } = useGetUserQuery('42'); ``` the Redux store gets a structure roughly like this: ```javascript state.api = { queries: { 'getUser("42")': { status: 'fulfilled', data: { id: 42, name: 'Tim' }, fulfilledTimeStamp: 1718256635100, }, }, mutations: {}, provided: { users: { '42': ['getUser("42")'] } }, } ``` That is, RTK Query stores: - the **query key** (`endpointName + arguments`); - the **resulting data** (`data`); - the **cache time**; - **references to components subscribed to that data**. --- ## 3. Key concept: Query Cache Key Each query forms a **unique cache key**, based on: - the endpoint name (`getUser`), - the arguments (`'42'`). Example: ```javascript const cacheKey = 'getUser("42")' ``` React components calling `useGetUserQuery('42')` subscribe to the same key. If data for that key already exists, RTK Query **takes it from the cache** instead of fetching again. --- ## 4. When RTK Query uses the cache vs. makes a new request | Scenario | What RTK Query does | |---|---| | Another component calls `useGetUserQuery('42')` | Uses the cache (a single source of truth) | | Fewer than `keepUnusedDataFor` seconds have passed since the last component unmounted | Still keeps the data in the cache | | More than `keepUnusedDataFor` seconds have passed | Removes the cache | | `refetch()` is called | Makes a new request, updates the cache | | An "invalidation" happens via a tag | Removes the cache and makes a new request | --- ## 5. `keepUnusedDataFor`: cache lifetime By default, RTK Query keeps data **in the cache for 60 seconds** after the last subscribed component unmounts. ```javascript builder.query({ query: () => '/posts', keepUnusedDataFor: 120, // keep data for 2 minutes }); ``` If another component requests `/posts` again within those 120 seconds, RTK Query **takes the data from the cache**, without a network request. --- ## 6. Tag-based cache and automatic invalidation RTK Query supports **tags** to manage the cache at the entity level (users, posts, etc.). ### Example: ```javascript const api = createApi({ baseQuery: fetchBaseQuery({ baseUrl: '/api' }), tagTypes: ['User'], endpoints: builder => ({ getUser: builder.query<User, number>({ query: id => `/user/${id}`, providesTags: (result, error, id) => [{ type: 'User', id }], }), updateUser: builder.mutation<void, User>({ query: user => ({ url: `/user/${user.id}`, method: 'PUT', body: user, }), invalidatesTags: (result, error, user) => [{ type: 'User', id: user.id }], }), }), }); ``` What happens: 1. `getUser(42)` caches data under the tag `{type: 'User', id: 42}`. 2. When `updateUser({id: 42, ...})` is called, RTK Query **invalidates the tag**. 3. All cached queries that provide that tag (`providesTags`) become **invalid**. 4. RTK Query **automatically refetches** the data. --- ## 7. Behavior with multiple components ```javascript function Profile() { const { data } = useGetUserQuery('42'); return <div>{data?.name}</div>; } function Sidebar() { const { data } = useGetUserQuery('42'); return <div>{data?.name}</div>; } ``` Both components use **the same cache key**, so there's just one request to the server. - The first component triggers the fetch. - The second gets the data **from the cache immediately**, without a request. - If one of them unmounts, the cache still lives until `keepUnusedDataFor` expires. --- ## 8. How RTK Query tracks freshness Each cached query has **metadata**: - `fulfilledTimeStamp` (time of the last update), - `isFetching`, - `isSuccess`, - `isError`, - `isUninitialized`. You can manually call: ```javascript refetch(); // updates the cache ``` or use: ```javascript pollingInterval: 10000 // automatically update every 10 seconds ``` --- ## 9. Cache at the Redux store level If you look into Redux DevTools, you see something like this: ```javascript state.api.queries["getUser(42)"] = { status: "fulfilled", data: { id: 42, name: "Tim" }, fulfilledTimeStamp: 1718256635100, originalArgs: 42, requestId: "getUser-42-1", } ``` Each cache entry lives independently and has its own TTL (time-to-live). --- ## 10. Summary: how RTK Query caches data | Mechanism | What it does | |---|---| | Cache by key (`endpoint + arguments`) | A single request per unique set of arguments | | TTL via `keepUnusedDataFor` | Keeps data after unmounting | | Tags (`providesTags` / `invalidatesTags`) | Granular updates on mutations | | `refetch` / `pollingInterval` | Refreshing stale data | | Redux store | All data is centrally cached in state | | Automatic reuse | Components reuse ready cache entries | --- ## Example of a full caching cycle 1. A component calls `useGetUserQuery(42)` -> RTK Query makes a request -> stores it in the store -> The component receives `data` 2. A second component calls `useGetUserQuery(42)` -> RTK Query sees the data already exists -> Returns it immediately (0ms) 3. The component unmounts -> RTK Query waits `keepUnusedDataFor` seconds 4. If the component mounts again within that time -> data is taken from the cache, without a fetch 5. If a mutation with `invalidatesTags` is called -> the corresponding cache entries are removed -> RTK Query does a refetch. --- ## Summary > RTK Query caches data **by a unique query key**, > stores it in the **Redux store**, > automatically **invalidates** it on changes, > and **reuses** it across components. **Cheat sheet:** - All data lives in the Redux store, a single source of truth. - `keepUnusedDataFor` controls the cache lifetime. - `providesTags` / `invalidatesTags` control automatic refetching. - Repeated calls to `useXxxQuery()` with the same arguments don't refetch the data.For the reviewerNote to the moderator (optional)Visible only to the moderator. Helps review go faster.