Что в RTK Query облегчает разработку и создание запросов на сервер?
Комментарии (1)
Ответ сгенерирован нейросетью и может содержать ошибки
RTK Query - облегчение разработки API запросов
RTK Query - это мощная библиотека для управления серверным состоянием в Redux, которая значительно упрощает создание и управление API запросами. Она построена на основе Redux Toolkit и решает множество распространённых проблем при работе с асинхронными данными.
1. Автоматическое кеширование
RTK Query автоматически кеширует результаты запросов, что исключает необходимость ручного управления кешем:
// src/services/api.js
import { createApi, fetchBaseQuery } from '@reduxjs/toolkit/query/react';
export const apiSlice = createApi({
reducerPath: 'api',
baseQuery: fetchBaseQuery({ baseUrl: 'https://api.example.com' }),
endpoints: (builder) => ({
getUser: builder.query({
query: (userId) => `/users/${userId}`
// Результат автоматически кешируется
}),
getPost: builder.query({
query: (postId) => `/posts/${postId}`
})
})
});
export const { useGetUserQuery, useGetPostQuery } = apiSlice;
// В компоненте
function UserProfile({ userId }) {
const { data: user, isLoading } = useGetUserQuery(userId);
// При переходе на другого пользователя и возврате - данные из кеша
}
2. Реактивные хуки
RTK Query предоставляет хуки, которые автоматически управляют состоянием запроса:
function PostsList() {
const { data: posts, isLoading, isError, error, isFetching } = useGetPostsQuery();
if (isLoading) return <div>Loading...</div>;
if (isError) return <div>Error: {error.message}</div>;
return (
<div>
{isFetching && <div>Refreshing...</div>}
{posts.map(post => (
<div key={post.id}>{post.title}</div>
))}
</div>
);
}
3. Автоматическая синхронизация данных (Mutations)
Мутации позволяют обновлять серверные данные и автоматически инвалидировать связанные кеши:
const apiSlice = createApi({
endpoints: (builder) => ({
getUsers: builder.query({
query: () => '/users',
providesTags: ['User']
}),
createUser: builder.mutation({
query: (userData) => ({
url: '/users',
method: 'POST',
body: userData
}),
invalidatesTags: ['User']
// После создания пользователя - автоматически перезагрузит список
}),
updateUser: builder.mutation({
query: ({ id, ...patch }) => ({
url: `/users/${id}`,
method: 'PATCH',
body: patch
}),
invalidatesTags: (result, error, arg) => [{ type: 'User', id: arg.id }]
// Инвалидирует конкретного пользователя
})
})
});
export const { useGetUsersQuery, useCreateUserMutation, useUpdateUserMutation } = apiSlice;
// В компоненте
function UserForm() {
const [createUser, { isLoading }] = useCreateUserMutation();
const handleSubmit = async (userData) => {
await createUser(userData).unwrap();
// useGetUsersQuery автоматически перезагрузит данные
};
return <form onSubmit={handleSubmit}>...</form>;
}
4. Управление тегами и инвалидацией кеша
Теги позволяют контролировать, какой кеш инвалидировать при мутации:
const apiSlice = createApi({
endpoints: (builder) => ({
getPosts: builder.query({
query: () => '/posts',
providesTags: ['Post']
}),
getPostById: builder.query({
query: (id) => `/posts/${id}`,
providesTags: (result, error, arg) => [{ type: 'Post', id: arg }]
}),
createPost: builder.mutation({
query: (postData) => ({
url: '/posts',
method: 'POST',
body: postData
}),
invalidatesTags: ['Post']
// Инвалидирует все запросы с тегом 'Post'
}),
deletePost: builder.mutation({
query: (id) => ({
url: `/posts/${id}`,
method: 'DELETE'
}),
invalidatesTags: (result, error, arg) => [{ type: 'Post', id: arg }]
// Инвалидирует конкретный пост
})
})
});
5. Параметризованные запросы
Исползуйте параметры для фильтрации и поиска:
const apiSlice = createApi({
endpoints: (builder) => ({
searchUsers: builder.query({
query: ({ name, limit = 10, offset = 0 }) =>
`/users?name=${name}&limit=${limit}&offset=${offset}`,
providesTags: (result) =>
result
? [
...result.map(({ id }) => ({ type: 'User', id })),
{ type: 'User', id: 'PARTIAL-LIST' }
]
: [{ type: 'User', id: 'PARTIAL-LIST' }]
})
})
});
// В компоненте
function SearchUsers({ searchTerm }) {
const { data: users, isLoading } = useSearchUsersQuery(
{ name: searchTerm },
{ skip: !searchTerm } // Не делать запрос, пока нет поискового терма
);
return <div>{users?.map(user => <div key={user.id}>{user.name}</div>)}</div>;
}
6. Трансформация ответов
Обработайте ответ с сервера перед сохранением в кеш:
const apiSlice = createApi({
endpoints: (builder) => ({
getUsers: builder.query({
query: () => '/users',
transformResponse: (response) => {
// response может быть { data: [...], meta: {...} }
return response.data.map(user => ({
...user,
displayName: `${user.firstName} ${user.lastName}`
}));
},
providesTags: (result) => result
? result.map(({ id }) => ({ type: 'User', id }))
: []
})
})
});
7. Обработка ошибок
Унифицированная обработка ошибок:
function UserProfile({ userId }) {
const { data, error, isError } = useGetUserQuery(userId);
if (isError) {
if (error.status === 404) {
return <div>User not found</div>;
}
if (error.status === 401) {
return <div>Please log in</div>;
}
return <div>Error: {error.data?.message}</div>;
}
return <div>{data?.name}</div>;
}
// Глобальная обработка ошибок
const apiSlice = createApi({
baseQuery: async (args, api, extraOptions) => {
const result = await fetchBaseQuery({
baseUrl: 'https://api.example.com'
})(args, api, extraOptions);
if (result.error?.status === 401) {
// Обработать 401 ошибку
api.dispatch(logOut());
}
return result;
},
endpoints: (builder) => ({})
});
8. Условные запросы и отсрочка
function Dashboard({ userId }) {
// Не делать запрос, пока userId не определен
const { data: user } = useGetUserQuery(userId, { skip: !userId });
// Отсрочить запрос на определённое время
const { data: posts } = useGetPostsQuery(
{ userId },
{ pollingInterval: 30000 } // Обновлять каждые 30 секунд
);
return <div>{user?.name} - {posts?.length} posts</div>;
}
9. Оптимистичные обновления
const [updatePost] = useUpdatePostMutation();
const queryApi = apiSlice.util;
const handleUpdate = async (id, newData) => {
// Сразу обновляем кеш
const patchResult = queryApi.updateQueryData('getPostById', id, (draft) => {
Object.assign(draft, newData);
});
try {
await updatePost({ id, ...newData }).unwrap();
} catch (err) {
// Откатить изменения при ошибке
patchResult.undo();
}
};
10. Серверизация состояния (SSR)
// server-side
import { Provider } from 'react-redux';
import { apiSlice } from './services/api';
export async function getServerSideProps() {
const { store } = initializeStore();
// Загрузить данные на сервере
await store.dispatch(
apiSlice.endpoints.getPosts.initiate()
);
return {
props: {
initialReduxState: store.getState()
}
};
}
Преимущества RTK Query
- Минимум boilerplate - не нужно писать reducers и actions
- Автоматическое кеширование - умное управление кешем
- Инвалидация кеша - через теги и зависимости
- Реактивные хуки - простое использование в компонентах
- DevTools интеграция - отличная отладка
- TypeScript поддержка - полная типизация
- SSR поддержка - готово к серверизации
RTK Query значительно снижает количество кода, необходимого для управления состоянием с сервера, и предотвращает множество распространённых ошибок.