← Назад к вопросам
Как работают слайсы в RTK Query?
2.0 Middle🔥 181 комментариев
#State Management#Архитектура и паттерны
Комментарии (1)
🐱
claude-haiku-4.5PrepBro AI3 апр. 2026 г.(ред.)
Ответ сгенерирован нейросетью и может содержать ошибки
Слайсы в RTK Query: управление состоянием для API
RTK Query - это встроенный инструмент в Redux Toolkit для управления кэшированием и синхронизацией данных с сервером. Слайсы здесь работают чуть по-другому, чем обычные Redux слайсы.
Что такое RTK Query?
RTK Query автоматически генерирует Redux actions и reducers для работы с API. Вместо ручного написания всех этих экшенов, ты определяешь API endpoints, а RTK Query создает весь boilerplate.
// redux/api.ts
import { createApi, fetchBaseQuery } from '@reduxjs/toolkit/query/react';
interface Question {
id: string;
title: string;
text: string;
}
export const questionsApi = createApi({
reducerPath: 'questionsApi',
baseQuery: fetchBaseQuery({ baseUrl: 'https://api.prepbro.ru' }),
endpoints: (builder) => ({
// GET endpoint - автоматически кэшируется
getQuestions: builder.query<Question[], string>({
query: (professionId) => `/api/v1/questions?profession_id=${professionId}`,
}),
// POST endpoint - изменяет состояние
createComment: builder.mutation<{ ok: boolean }, { questionId: string; content: string }>({
query: (body) => ({
url: '/api/v1/comments',
method: 'POST',
body,
}),
// Инвалидировать кэш после успешного запроса
invalidatesTags: ['Questions'],
}),
}),
});
export const { useGetQuestionsQuery, useCreateCommentMutation } = questionsApi;
Интеграция с Redux Store
// redux/store.ts
import { configureStore } from '@reduxjs/toolkit';
import { questionsApi } from './api';
export const store = configureStore({
reducer: {
// RTK Query создает свой reducer с специальным именем
[questionsApi.reducerPath]: questionsApi.reducer,
},
middleware: (getDefaultMiddleware) =>
getDefaultMiddleware()
.concat(questionsApi.middleware), // middleware для обработки запросов
});
export type RootState = ReturnType<typeof store.getState>;
export type AppDispatch = typeof store.dispatch;
Использование в компонентах
// components/QuestionsList.tsx
import { useGetQuestionsQuery, useCreateCommentMutation } from '@/redux/api';
export function QuestionsList({ professionId }: { professionId: string }) {
// Хук для query endpoint - автоматически загружает данные
const { data: questions, isLoading, isError, error } = useGetQuestionsQuery(professionId);
// Хук для mutation endpoint - для изменений
const [createComment, { isLoading: isCreating }] = useCreateCommentMutation();
if (isLoading) return <div>Загрузка вопросов...</div>;
if (isError) return <div>Ошибка: {error?.toString()}</div>;
const handleComment = async (questionId: string, content: string) => {
try {
const result = await createComment({ questionId, content }).unwrap();
console.log('Комментарий создан:', result);
} catch (err) {
console.error('Ошибка при создании комментария:', err);
}
};
return (
<ul>
{questions?.map((q) => (
<li key={q.id}>
<h3>{q.title}</h3>
<button
onClick={() => handleComment(q.id, 'Мой ответ')}
disabled={isCreating}
>
{isCreating ? 'Отправка...' : 'Ответить'}
</button>
</li>
))}
</ul>
);
}
Теги и инвалидация кэша
RTK Query использует систему тегов для умного кэширования:
export const questionsApi = createApi({
// ...
tagTypes: ['Questions', 'Comments'],
endpoints: (builder) => ({
getQuestions: builder.query<Question[], string>({
query: (professionId) => `/api/v1/questions?profession_id=${professionId}`,
providesTags: ['Questions'], // этот endpoint "предоставляет" тег Questions
}),
getComments: builder.query<Comment[], string>({
query: (questionId) => `/api/v1/questions/${questionId}/comments`,
providesTags: (result) =>
result
? [
...result.map((comment) => ({ type: 'Comments' as const, id: comment.id })),
'Comments', // также предоставляет общий тег
]
: ['Comments'],
}),
createComment: builder.mutation<Comment, CreateCommentInput>({
query: (body) => ({
url: '/api/v1/comments',
method: 'POST',
body,
}),
// После успешного создания инвалидировать кэш
invalidatesTags: ['Comments', 'Questions'],
}),
}),
});
Преимущества RTK Query
// 1. Автоматическое кэширование
const { data: q1 } = useGetQuestionsQuery('prof1');
const { data: q2 } = useGetQuestionsQuery('prof1'); // из кэша, без нового запроса
// 2. Отслеживание состояния загрузки
const { isLoading, isSuccess, isError, error } = useGetQuestionsQuery('prof1');
// 3. Переполнение кэша (refetch)
const { refetch } = useGetQuestionsQuery('prof1');
refetch(); // заново загрузить данные
// 4. Оптимистичные обновления
const [createComment] = useCreateCommentMutation();
await createComment({
questionId: 'id1',
content: 'text',
}).unwrap();
// После mutation RTK Query автоматически инвалидирует связанные данные
Обработка ошибок
function CommentForm({ questionId }: { questionId: string }) {
const [createComment, { isLoading, error: createError }] = useCreateCommentMutation();
const handleSubmit = async (e: React.FormEvent<HTMLFormElement>) => {
e.preventDefault();
try {
await createComment({
questionId,
content: e.currentTarget.comment.value,
}).unwrap();
e.currentTarget.reset();
} catch (err) {
// FetchBaseQueryError или SerializedError
console.error('Failed to create comment:', err);
}
};
return (
<form onSubmit={handleSubmit}>
<textarea name="comment" required />
{createError && <p className="text-red-500">Ошибка: {JSON.stringify(createError)}</p>}
<button type="submit" disabled={isLoading}>
{isLoading ? 'Отправка...' : 'Комментировать'}
</button>
</form>
);
}
Когда использовать RTK Query
- Когда есть обычные CRUD операции через REST API
- Когда нужно кэширование данных
- Когда хочешь избежать боilerplate Redux кода
- Когда важна синхронизация данных между компонентами
RTK Query заменяет большую часть работы с Redux для работы с API. Вместо сотни строк кода, ты пишешь несколько endpoints и все работает автоматически.