Embarking on the development of Single Page Applications (SPAs), we encountered numerous challenges in maintaining synchronization between our web application and the backend server while ensuring the presentation of only the most recent and updated data to our users. These challenges were compounded by the necessity to address specific behaviors such as displaying loading states, reusing API responses, and managing synchronization after certain backend requests.
In our quest to overcome these hurdles, we discovered RTK Query—a powerful tool that simplified our data fetching processes & revolutionized our approach to data management.
Our journey
Our journey with RTK Query stemmed from a genuine need for a robust solution to our data management challenges. A few pages in our existing React application were experiencing slow loading times due to fetching data from the backend. To optimize performance, it became necessary to cache responses so that we did not have to call the API again on subsequent page visits.
However, our existing application was heavily dependent on Redux. We were utilizing custom redux middleware to support the following features:
- Generation of toast messages to show the success or failure of different API calls.
- Handling automatic logouts when an unauthorized API gets called.
- Avoiding API calls when the plan to use the platform is not renewed with the latest payment.
One of the pivotal moments in our journey was the realization of RTK Query’s seamless integration with Redux—the state management library we were already using. This integration proved to be a significant change, as it allowed us to leverage the full power of RTK Query while seamlessly integrating it into our existing Redux setup.
RTK Query’s comprehensive support for complex data management scenarios proved invaluable to us. Whether it was caching data, synchronizing updates, or handling multiple API calls, RTK Query provided us with the tools needed to tackle these challenges without disturbing the existing redux setup.
What is RTK Query?
RTK Query is a powerful data fetching and caching tool. It is used for fetching, caching, synchronizing, and updating server state in web applications. It is intended to simplify the common case of loading the data and eliminating the need to handwrite data fetching logic.
RTK Query is provided as an optional addon within @reduxjs/toolkit.
Prerequisites
- React 16.8 or above: RTK Query relies on React hook, which was introduced in React 16.8 version
- @reduxjs/toolkit 1.5 or above: RTK Query was introduced in @reduxjs/toolkit version1.5, But it is recommended to use latest @reduxjs/toolkit version so that we can utilize latest RTK Query features
Steps to Setup RTK Query with Existing React App
Please follow the steps below to setup RTK Query inside the existing react application. Here we are working with a new react (v18.2) application setup with Create React App (CRA).
1. Installing Required Dependencies:
To get started with RTK Query, please install below dependencies inside react application
yarn add @reduxjs/toolkit
yarn add react-redux
2. Create API Service:
This will be the base implementation for your service. Ideally, your application should have only one service per base URL. With RTK Query you define your entire API definition in one place. The createApi function should be imported from @reduxjs/toolkit/query/react, which is a react specific endpoint. It autogenerates react specific hooks, which can be used for data fetching)
(Note: Here, we have configured baseURL to the localhost URL to which the backend is running. Also, the endpoints key is configured with a function which returns an empty object. We will configure endpoint specific to page in our application like the way we configure slice.)
3. Configure Store:
To use the base API service, we now need to configure the redux store using @redixjs/toolkit. RTK Query generates a slice reducer, which should be included in the redux root reducer. It also generates middleware, which also needs to be included into the redux root middleware. It enables caching, invalidation, polling, and many more features provided by RTK Query.
(Note: Here we have imported applicationAPI exported from src/service.ts.)
4. Wrap Application with Provider:
This is required to provide redux store to your application.
5. Create API Endpoints:
This is a code-splitting technique used in RTK Query, which enables developers to create API endpoints specific to the application page (like creating a slice).
RTK Query generates a hook specific to each endpoint defined, which can then be imported into a component file to trigger the API call.
(Note: Here, we have created an API endpoint to GET the latest release date. LatestRelease type defines the type of data received from API response and void type to specify the type of first input parameter of useGetLatestReleaseQuery)
6. Using Query Inside Component:
Component can then import hooks exported from API endpoint. This function returns data along with some additional info which can be used to show additional status like loading, fetching, error etc.
When to use?
1. Project with existing Redux Setup: You have an existing application that uses Redux, and you want to simplify data fetching inside that application. (You want to implement caching on selective web pages without affecting the existing redux setup)
2. Integration with Redux Features: If you need to integrate redux features inside your application (like middleware to implement toast messages), then RTK Query is a viable choice as it integrates seamlessly with Redux.
3. Complex data management: Often in web application we have complex data storing requirement in which along with cached data we need to use some third-party tool to store data.
When not to use?
1. Project without Redux: If your project does not use Redux to manage data and you want to implement data caching and fetching. In this case, using a third-party caching tool that only serves caching and fetching purposes should be a way to go.
2. No complex data management required: In simple web application where data management is not really needed.
3. Need lightweight solution for data management: As RTK Query is provided as an optional addon with @reduxjs/toolkit, you always get redux store management along with RTK Query.
Comparison with other tools
RTK-Query | React Query | SWR | |
Platform Requirement | Redux | React | React |
Supported Frameworks | Any | React | React |
Supported Query Syntax | Promise, REST, GraphQL | Promise, REST, GraphQL | Promise, REST, GraphQL |
React Suspense | Not Supported | Supported | Supported |
API Definition Location | External Config | Component, External Config | Component |
Auto Garbage Collection | Supported | Supported | No Supported |
Query Cancellation | Not Supported | Supported | Not Supported |
Links | Github, NPM | Github, NPM | Github, NPM |
For more detailed comparison, visit Comparison on React Query Documentation, Comparison on RTK Query Documentation
Advantages to RTK Query over other Caching Tools:
- With RTK Query, you define your hook in a centralized place by defining the API Slice with multiple endpoints. This enables you to have your entire API-related logic in a separate file.
- As RTK Query dispatches normal redux actions as requests are processed, all the actions are visible in the DevTools.
- RTK Query has a tiny fetch wrapper (fetchBaseQuery) which it uses to trigger the API calls. We can easily write custom implementation of fetch using axios or any other library of our choice. See documentation here
- RTK Query comes with Redux, which is a state management tool.
- RTK Query functions with any UI (User Interface) layer as it is UI-agnostic.
Conclusion
RTK Query is the best solution for your data caching, fetching, and synchronization needs when you have an existing React application which uses the redux toolkit. In this case, the developer does not need to add any extra dependency to support data caching. However, RTK Query might have a steeper learning curve for developers unfamiliar with Redux concept.
In general cases, you can use RTK Query as it provides a great way to organize your code in a more structured way by using their injectEndpoints feature. This enables developers to separate API-related logic from component logic.