← Назад к вопросам
Как происходит валидация данных в RTK Query?
1.8 Middle🔥 171 комментариев
#JavaScript Core
Комментарии (1)
🐱
claude-haiku-4.5PrepBro AI3 апр. 2026 г.(ред.)
Ответ сгенерирован нейросетью и может содержать ошибки
Валидация данных в RTK Query
RTK Query (Redux Toolkit Query) — это инструмент для управления данными с сервера, встроенный в Redux Toolkit. Валидация в RTK Query происходит на разных уровнях: валидация ответа, кэширование и синхронизация состояния.
Как работает RTK Query?
RTK Query автоматически управляет:
- Загрузкой данных
- Кэшированием
- Сихронизацией
- Ошибками
- Переобновлением при необходимости
// Базовая настройка RTK Query
import { createApi, fetchBaseQuery } from '@reduxjs/toolkit/query/react';
const api = createApi({
reducerPath: 'api',
baseQuery: fetchBaseQuery({ baseUrl: 'https://api.example.com' }),
endpoints: (builder) => ({
getUser: builder.query({
query: (id) => `/users/${id}`
})
})
});
export const { useGetUserQuery } = api;
Валидация ответа — transformResponse
1. Трансформация и валидация в одном месте
const api = createApi({
// ...
endpoints: (builder) => ({
getUser: builder.query({
query: (id) => `/users/${id}`,
transformResponse: (data) => {
// Валидируем структуру данных
if (!data.id || !data.email) {
throw new Error('Invalid user data structure');
}
// Трансформируем для удобства
return {
...data,
fullName: `${data.firstName} ${data.lastName}`,
isActive: Boolean(data.status === 'active')
};
}
})
})
});
2. Валидация с TypeScript
interface User {
id: number;
email: string;
firstName: string;
lastName: string;
status: 'active' | 'inactive';
}
const api = createApi({
endpoints: (builder) => ({
getUser: builder.query<User, number>({
query: (id) => `/users/${id}`,
transformResponse: (data: any): User => {
// TypeScript поможет отловить ошибки типов
if (!data.id || typeof data.id !== 'number') {
throw new Error('User ID must be a number');
}
if (!['active', 'inactive'].includes(data.status)) {
throw new Error('Invalid status');
}
return data as User;
}
})
})
});
Валидация на уровне query
1. Проверка параметров
const api = createApi({
endpoints: (builder) => ({
getUsers: builder.query({
query: (params) => {
// Валидируем входные параметры
if (!params.page || params.page < 1) {
throw new Error('Page must be >= 1');
}
if (params.limit > 100) {
throw new Error('Limit cannot exceed 100');
}
return {
url: '/users',
params: {
page: params.page,
limit: params.limit || 10
}
};
}
})
})
});
Валидация в компоненте
import { useGetUserQuery } from './api';
function UserProfile({ userId }) {
const { data, isLoading, error } = useGetUserQuery(userId);
// RTK Query автоматически обрабатывает ошибки
if (error) {
return <div>Error: {error.message}</div>;
}
if (isLoading) {
return <div>Loading...</div>;
}
// TypeScript убедится, что data имеет правильный тип
return (
<div>
<h1>{data.fullName}</h1>
<p>Email: {data.email}</p>
<p>Status: {data.isActive ? 'Active' : 'Inactive'}</p>
</div>
);
}
Валидация кэша — cache invalidation
1. Инвалидация при мутациях
const api = createApi({
endpoints: (builder) => ({
getUsers: builder.query({
query: () => '/users'
}),
createUser: builder.mutation({
query: (userData) => ({
url: '/users',
method: 'POST',
body: userData
}),
// После создания пользователя обновляем список
invalidatesTags: ['User']
})
})
});
// Правильная валидация
const api = createApi({
tagTypes: ['User'],
endpoints: (builder) => ({
getUsers: builder.query({
query: () => '/users',
providesTags: ['User'] // Помечаем кэш тегом
}),
createUser: builder.mutation({
query: (userData) => ({
url: '/users',
method: 'POST',
body: userData
}),
invalidatesTags: ['User'] // При успехе инвалидируем тег
})
})
});
2. Детальная инвалидация
const api = createApi({
tagTypes: ['User', 'Posts'],
endpoints: (builder) => ({
// Получение одного пользователя
getUser: builder.query({
query: (id) => `/users/${id}`,
providesTags: (result, error, arg) => [
{ type: 'User', id: arg }
]
}),
// Получение всех пользователей
getUsers: builder.query({
query: () => '/users',
providesTags: () => ['User']
}),
// Обновление пользователя
updateUser: builder.mutation({
query: ({ id, ...patch }) => ({
url: `/users/${id}`,
method: 'PATCH',
body: patch
}),
// Инвалидируем конкретного пользователя и весь список
invalidatesTags: (result, error, arg) => [
{ type: 'User', id: arg.id },
'User'
]
})
})
});
Обработка ошибок валидации
const api = createApi({
endpoints: (builder) => ({
createUser: builder.mutation({
query: (userData) => ({
url: '/users',
method: 'POST',
body: userData
}),
// Кастомная обработка ошибок
async onQueryStarted(arg, { dispatch, queryFulfilled }) {
try {
const { data } = await queryFulfilled;
console.log('User created:', data);
} catch (error) {
if (error.status === 422) {
// Ошибка валидации на сервере
console.log('Validation errors:', error.data.errors);
}
}
}
})
})
});
Реальный пример с полной валидацией
import { createApi, fetchBaseQuery } from '@reduxjs/toolkit/query/react';
import { z } from 'zod'; // для валидации схемы
// Определяем схему валидации
const UserSchema = z.object({
id: z.number().int().positive(),
email: z.string().email(),
firstName: z.string().min(1),
lastName: z.string().min(1),
status: z.enum(['active', 'inactive'])
});
const api = createApi({
reducerPath: 'api',
baseQuery: fetchBaseQuery({ baseUrl: 'https://api.example.com' }),
tagTypes: ['User'],
endpoints: (builder) => ({
// Получение пользователя с валидацией
getUser: builder.query({
query: (id) => {
if (!Number.isInteger(id) || id <= 0) {
throw new Error('Invalid user ID');
}
return `/users/${id}`;
},
transformResponse: (data) => {
// Валидируем структуру
return UserSchema.parse(data);
},
providesTags: (result) => [
{ type: 'User', id: result?.id }
]
}),
// Создание пользователя с валидацией
createUser: builder.mutation({
query: (userData) => {
// Валидируем входные данные
const validated = UserSchema.omit({ id: true }).parse(userData);
return {
url: '/users',
method: 'POST',
body: validated
};
},
invalidatesTags: ['User']
})
})
});
В компоненте React с полной валидацией
function UserForm() {
const [createUser, { isLoading, error }] = useCreateUserMutation();
const [formData, setFormData] = React.useState({});
const handleSubmit = async (e) => {
e.preventDefault();
try {
// RTK Query автоматически валидирует данные
await createUser(formData).unwrap();
// Успешно создано
} catch (err) {
// Обработка ошибок валидации
if (err.status === 422) {
console.log('Validation failed:', err.data);
}
}
};
return (
<form onSubmit={handleSubmit}>
{error && <div className="error">{error.message}</div>}
<input
value={formData.email}
onChange={(e) => setFormData({...formData, email: e.target.value})}
/>
<button type="submit" disabled={isLoading}>Create</button>
</form>
);
}
Вывод
Валидация в RTK Query происходит на разных уровнях:
- transformResponse — валидация и трансформация ответа
- query параметры — проверка входных данных
- Tags и invalidation — валидация кэша
- TypeScript — статическая валидация типов
- Error handling — обработка ошибок валидации
RTK Query обеспечивает надёжное управление данными с полной валидацией на каждом этапе.