Где лучше писать запросы к серверу в React?
API и асинхронность
Короткий ответ 2020-х: не в компонентах руками, а в специализированном слое — React Query/RTK Query или лоадерах фреймворка; сами HTTP-вызовы — в отдельном API-модуле.
Слои запроса
API-слой (обязателен при любом подходе). Функции запросов отдельно от UI: api/users.ts с getUser(id), базовый клиент (fetch/axios) с авторизацией и обработкой ошибок. Компоненты не знают про URL и заголовки.
Слой выполнения — варианты:
- TanStack Query / RTK Query (рекомендация по умолчанию). Запрос описывается декларативно:
useQuery({ queryKey: ['user', id], queryFn: () => api.getUser(id) }). Кеш, дедупликация, статусы, ретраи, инвалидация — из коробки; компонент только читает данные. - Лоадеры маршрутов (React Router 6.4+, Remix, Next.js App Router): данные грузятся при навигации до рендера страницы; в Next.js — прямо в серверных компонентах (
awaitв теле). - Ручной useEffect + useState — легально для мелочей и обучения, но в проде быстро обрастает проблемами: гонки, дубли запросов (StrictMode), отсутствие кеша, бойлерплейт статусов.
Куда запросы писать НЕ надо
- В теле компонента (вне эффектов) — рендер обязан быть чистым; запрос на каждый рендер.
- В useMemo/useCallback — то же нарушение чистоты.
- Мутации — в обработчиках событий (или useMutation), не в эффектах.
Итоговая структура
api/ (HTTP-функции) → hooks/ (useUser = обёртка useQuery) → компоненты (вызов хука)Коротко для собеседования
HTTP-вызовы — в отдельном API-модуле; выполнение — через React Query/RTK Query (кеш, статусы, дедупликация) или лоадеры маршрутов/серверные компоненты; ручной fetch в useEffect — только для простых случаев с cleanup от гонок. В теле компонента и useMemo запросам не место.