Part 3: Introduction to RTK Query
In this part we will cover RTK query
1. What is RTK Query?
While Redux Toolkit provides powerful tools to manage state and asynchronous logic, it still requires significant boilerplate code to handle data fetching and caching. RTK Query, introduced in Redux Toolkit v1.6, aims to solve this problem by providing a set of powerful tools for efficient data fetching and caching with minimal setup.
Key features of RTK Query:
- Data Fetching and Caching: Automatically handles caching, invalidation, and refetching.
- Optimistic Updates and Realtime Synchronization: Easily manage optimistic updates and real-time data synchronization.
- Declarative and Simple API: Intuitive API design with minimal boilerplate code.
- Integrated with Redux Toolkit: Built on top of Redux Toolkit, allowing seamless integration.
2. Setting Up RTK Query
To get started with RTK Query, we need to define an API service that specifies how to fetch data and what endpoints are available. Let’s create an example using a simple posts API.
Step 1: Define an API Service
Create a new file named postsApi.js
in the features/posts
directory. This file will define the API endpoints for fetching and mutating posts.
// src/features/posts/postsApi.js
import { createApi, fetchBaseQuery } from '@reduxjs/toolkit/query/react';
// Define an API service using RTK Query
export const postsApi = createApi({
reducerPath: 'postsApi',
baseQuery: fetchBaseQuery({ baseUrl: 'https://jsonplaceholder.typicode.com/' }),
endpoints: (builder) => ({
fetchPosts: builder.query({
query: () => 'posts',
}),
addPost: builder.mutation({
query: (newPost) => ({
url: 'posts',
method: 'POST',
body: newPost,
}),
}),
}),
});
// Export hooks for usage in functional components
export const { useFetchPostsQuery, useAddPostMutation } = postsApi;
Explanation:
-
createApi
: This function is used to define an API service. It generates an API slice, automatically managing the store, reducers, and actions for you. -
baseQuery
: A function that defines the base URL for your API.fetchBaseQuery
is a lightweight wrapper around the standardfetch
API. -
endpoints
: A function that defines the endpoints for the API. We define two endpoints here:fetchPosts
for querying data andaddPost
for creating a new post.
Step 2: Integrate API Service into the Redux Store
Add the postsApi
reducer to the store and configure middleware to enable caching and invalidation.
Update store.js
to integrate postsApi
:
// src/app/store.js
import { configureStore } from '@reduxjs/toolkit';
import { postsApi } from '../features/posts/postsApi';
const store = configureStore({
reducer: {
// Add the generated reducer as a specific top-level slice
[postsApi.reducerPath]: postsApi.reducer,
},
// Adding the api middleware enables caching, invalidation, polling, and other features of RTK Query
middleware: (getDefaultMiddleware) =>
getDefaultMiddleware().concat(postsApi.middleware),
});
export default store;
3. Using RTK Query in Components
RTK Query generates custom hooks based on the endpoints defined in the API service. These hooks are used to perform data fetching, mutations, and manage caching automatically.
Step 1: Fetching Data with useFetchPostsQuery
Create a PostsList.js
component to fetch and display the list of posts.
// src/features/posts/PostsList.js
import React from 'react';
import { useFetchPostsQuery } from './postsApi';
const PostsList = () => {
const { data: posts, error, isLoading } = useFetchPostsQuery();
if (isLoading) return <p>Loading...</p>;
if (error) return <p>An error occurred: {error.message}</p>;
return (
<section>
<h2>Posts</h2>
<ul>
{posts.map((post) => (
<li key={post.id}>{post.title}</li>
))}
</ul>
</section>
);
};
export default PostsList;
Explanation:
-
useFetchPostsQuery
: A custom hook generated by RTK Query for thefetchPosts
endpoint. It returns an object containing the fetched data (data
), loading state (isLoading
), and error state (error
). - The component conditionally renders loading, error, or data states based on the hook output.
Step 2: Adding Data with useAddPostMutation
Create a AddPostForm.js
component to add new posts using the addPost
mutation.
// src/features/posts/AddPostForm.js
import React, { useState } from 'react';
import { useAddPostMutation } from './postsApi';
const AddPostForm = () => {
const [addPost, { isLoading }] = useAddPostMutation();
const [title, setTitle] = useState('');
const [content, setContent] = useState('');
const handleSubmit = async (e) => {
e.preventDefault();
if (title && content) {
await addPost({ title, body: content }).unwrap();
setTitle('');
setContent('');
}
};
return (
<section>
<h2>Add a New Post</h2>
<form onSubmit={handleSubmit}>
<input
type="text"
value={title}
onChange={(e) => setTitle(e.target.value)}
placeholder="Post Title"
/>
<textarea
value={content}
onChange={(e) => setContent(e.target.value)}
placeholder="Post Content"
/>
<button type="submit" disabled={isLoading}>
{isLoading ? 'Adding...' : 'Add Post'}
</button>
</form>
</section>
);
};
export default AddPostForm;
Explanation:
-
useAddPostMutation
: A custom hook generated by RTK Query for theaddPost
mutation. It provides a function (addPost
) to trigger the mutation and a loading state (isLoading
). -
unwrap()
: Allows us to unwrap the resolved or rejected payload from the mutation to handle side effects after the request.
4. Handling Cache, Errors, and Optimistic Updates
RTK Query automatically handles caching, error states, and invalidates the cache when mutations occur. You can further customize the behavior with tags and other configurations.
Step 1: Using providesTags
and invalidatesTags
Modify the postsApi
to use tags for cache invalidation:
// src/features/posts/postsApi.js
import { createApi, fetchBaseQuery } from '@reduxjs/toolkit/query/react';
export const postsApi = createApi({
reducerPath: 'postsApi',
baseQuery: fetchBaseQuery({ baseUrl: 'https://jsonplaceholder.typicode.com/' }),
tagTypes: ['Post'],
endpoints: (builder) => ({
fetchPosts: builder.query({
query: () => 'posts',
providesTags: (result) =>
result ? result.map(({ id }) => ({ type: 'Post', id })) : ['Post'],
}),
addPost: builder.mutation({
query: (newPost) => ({
url: 'posts',
method: 'POST',
body: newPost,
}),
invalidatesTags: ['Post'],
}),
}),
});
export const { useFetchPostsQuery, useAddPostMutation } = postsApi;
Explanation:
-
providesTags
: This is used to tag the data fetched from thefetchPosts
query. It helps in efficiently invalidating the cache when new data is added. -
invalidatesTags
: This is used in theaddPost
mutation to invalidate the cache and refetch the updated data.
5. Conclusion and Next Steps
In this part, we explored how to use RTK Query to handle data fetching and caching in Redux applications. We covered setting up an API service, defining endpoints, and using generated hooks for querying and mutating data. RTK Query simplifies data fetching and state management with minimal code, making it a powerful tool for modern Redux applications.
In the next part, we'll dive into Advanced Topics in RTK Query, such as customizing queries, using baseQuery
, handling authentication, and optimizing performance.
Stay tuned for Part 4: Advanced Topics in RTK Query!
Top comments (0)