← Назад к вопросам

Как происходит валидация данных в 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 происходит на разных уровнях:

  1. transformResponse — валидация и трансформация ответа
  2. query параметры — проверка входных данных
  3. Tags и invalidation — валидация кэша
  4. TypeScript — статическая валидация типов
  5. Error handling — обработка ошибок валидации

RTK Query обеспечивает надёжное управление данными с полной валидацией на каждом этапе.

Как происходит валидация данных в RTK Query? | PrepBro