This content originally appeared on Bits and Pieces - Medium and was authored by Madushika Perera
How to cache data using RTK for better performance
Redux is one of the best state managing methods for React. However, developers find it difficult to manage data fetching and caching with Redux due to the lack of inbuilt support.
In this article, I will discuss how we can use Redux-Tool-Kit Query (RTK Query) to simplify the data fetching and caching of React applications.
What is RTK Query
RTK Query is a powerful server data caching solution explicitly built for Redux Toolkit.
It is built on top of the Redux Toolkit and uses Redux internally for its architecture. RTK Query takes inspiration from many other excellent libraries like React Query, Apollo, Urql, and SWR.
RTK Query uses queries and mutations to improve data fetching and caching.
- Queries — This is the most common use case for RTK Query. You can use query operations with any data fetching library of your choice.
- Mutations — A mutation is used to send updates to the server and replicate the same in the local cache.
In addition to that, it provides inbuilt support for error handling and optimistic updates.
Why We Should Use RTK Query
As I mentioned, the main reason behind the introduction of RTK Query was to simplify the data fetching and caching process in React applications. But, that is not the only reason to use RTK Query.
- RTK Query is UI-agnostic. It can be integrated with any framework capable of using Redux (Vue.js, Svelte, Angular, etc.)
- Built with TypeScript, so it has first-class types support.
- Supports OpenAPI and GraphQL.
- Supports React Hooks.
- Provides Cache lifecycle, which enables streaming updates via WebSockets.
- To utilize the full power of Redux DevTools. It allows you to track the history of state changes over time.
- Very Small bundle size depending on whether you have RTK already in your project (~ 2KB).
Data Fetching and Caching with RTK Query
I think now you understand what RTK query is and the reasons behind its introduction, So, let’s see how we can fetch and cache data using RTK queries.
1. Data Fetching
Data fetching is the most common use case of RTK Query. By default, RTK Query uses a method called fetchBaseQuery to fetch data from services. It is a lightweight fetch wrapper that handles request headers and responses just like fetch and Axios.
If fetchBaseQuery doesn’t meet your expectations, you can customize the behavior with a wrapper function to handle any special requirement of your service.
To Query data using fetchBaseQuery, you need to define Query endpoints under the endpoints section of createApi.
Note: CreateApi is a core functionality of RTK Query. It allows to define endpoints and describe how to retrieve data.
import { createApi, fetchBaseQuery } from '@reduxjs/toolkit/query';
const api = createApi({
reducerPath: 'pokemonApi',
baseQuery: fetchBaseQuery({
baseUrl: 'https://example.org/',
prepareHeaders: (headers, {getState}) => {
const token = getState().auth.token;
if (token) {
headers.set('Authorization', `Bearer ${token}`)
}
return headers;
}
}),
keepUnusedDataFor: 30,
tagTypes:['Pokemons']
endpoints: build => ({
getPokemons: build.query({
query: () => (`/getpokemons`),
transformResponse: (response) => response.data,
providesTags: ['Pokemons'],
}),
createUser: build.mutation({
query: (request) => ({
url: '/createpokemon',
method: 'POST',
body: request,
}),
invalidatesTags: ['Pokemons'],
}),
}),
});
export const {useGetPokemonsQuery, useCreatePokemonMutation} = api;
export default api;
In the above code, I have defined the Query endpoints with some additional attributes to make things even easier:
- transformResponse — Allows manipulation of the data returned by a query or mutation.
- keepUnusedDataFor — To configure the data expiration time.
- tagTypes — These tags will be used by RTK Query as keys to cache data.
- invalidatesTags — These tags will be used to invalidate the cached data when a mutation occurs.
Finally, you can export the Query(useGetPokemonsQuery) and the Mutation(useCreatePokemonMutation) from this API.
2. Data Caching
Now, let’s see how we use the above API in our store to cache data.
import {configureStore} from '@reduxjs/toolkit';
import api from './api';
import authReducer from './slices/auth'; // Define all reducers
const reducer = {
[api.reducerPath]: api.reducer,
auth: authReducer,
};
export const store = configureStore({
reducer,
middleware: (getDefaultMiddleware) => getDefaultMiddleware().concat(api.middleware),
devTools: process.env.NODE_ENV !== 'production',
});
setupListeners(store.dispatch);
In the above example, I have imported the API created using createApi. Then, I have passed its reducerPath and reducer values to configureStore to initialize the store.
After creating the store, we can consume it inside the components like below:
export const PokemonList = () => {
const { data: pokemons, isFetching, isLoading } = useGetPokemonsQuery({
pollingInterval: 3000,
refetchOnMountOrArgChange: true,
skip: false,
})
if (isLoading) return <div>Loading...</div>
if (pokemons.lenght<=0) return <div>Missing pokemons!</div>
return (
<div>
{isFetching ? '...refetching' : ''}
{pokemons && pokemons.map((pokemon)=>{
return <li key={pokemon.id}>{pokemon.name}-{pokemon.power}</li>
})}
</div>
)
}
In the above component, I have fetched data from a REST endpoint using the useGetPokemonsQuery, exported from the API. Also, I have used an additional attribute named pollingInterval to invoke the query every 3 seconds.
In addition to that, each query and mutation will provide you with a server state that can be used to display as placeholders or loaders when fetching data.
- isUninitialized: indicate that Query has not started yet.
- isLoading: the Query is currently loading for the first time. No data yet.
- isFetching: Query is now fetching but might have data from an earlier request.
- isSuccess: The Query has data from a successful load.
- isError: The Query is currently in an “error” state.
Tip: Build Micro Frontends with components
Just like Microservices, Microfrontends are a great way to speed up and scale app development, with independent deployments, decoupled codebases, and autonomous teams.
Bit offers a great developer experience for building component-driven Micro frontends. Build components, collaborate, and compose applications that scale. Give it a try →
Bit: The platform for the modular web
Comparison between RTK Query and React Query
Even though RTK Query looks similar to React Query, there are some differences in their approaches.
For example, React Query uses a manual cached key for invalidation and caches by user-defined query keys, while RTK Query uses declarative data invalidations and creates cache keys via endpoints and arguments.
Therefore, I thought of comparing the core features of Redux Query and RTK Query. The following chart will give you a clear understanding of their similarities and differences.
Conclusion
RTK Query can be considered as one of the most awaited additions to the redux domain. It reduces all the hassle of writing code for fetching and caching logic in our projects.
So, I invite you to try RTK Query in your next project and share your thoughts in the comments section.
Thank you for reading !!!
Learn More
- React Query — An Underrated State Management Tool
- React Context API - A Replacement for Redux?
- 5 Alternatives to React Redux in 2020
Frontend Caching with Redux Toolkit Query was originally published in Bits and Pieces on Medium, where people are continuing the conversation by highlighting and responding to this story.
This content originally appeared on Bits and Pieces - Medium and was authored by Madushika Perera
Madushika Perera | Sciencx (2021-12-06T15:24:43+00:00) Frontend Caching with Redux Toolkit Query. Retrieved from https://www.scien.cx/2021/12/06/frontend-caching-with-redux-toolkit-query/
Please log in to upload a file.
There are no updates yet.
Click the Upload button above to add an update.