← Назад к вопросам
В каких action делал REST запросы
1.3 Junior🔥 171 комментариев
#State Management#Браузер и сетевые технологии
Комментарии (1)
🐱
claude-haiku-4.5PrepBro AI2 апр. 2026 г.(ред.)
Ответ сгенерирован нейросетью и может содержать ошибки
REST запросы в action creators (Redux/State Management)
Ответ: В async action creators (thunks) или middleware.
Вот как я это делаю в modern React проектах:
Redux Thunk (классический подход)
// actions/users.js
import axios from 'axios';
// Async action creator (thunk)
export const fetchUsers = () => async (dispatch) => {
// Dispatch начало загрузки
dispatch({ type: 'USERS_LOADING' });
try {
// REST запрос ЗДЕСЬ
const response = await axios.get('/api/v1/users');
// Dispatch успешно
dispatch({
type: 'USERS_SUCCESS',
payload: response.data
});
} catch (error) {
// Dispatch ошибку
dispatch({
type: 'USERS_ERROR',
payload: error.message
});
}
};
// В компоненте
import { useDispatch } from 'react-redux';
function UserList() {
const dispatch = useDispatch();
useEffect(() => {
dispatch(fetchUsers());
}, [dispatch]);
// render...
}
Redux Saga (для сложной логики)
// sagas/users.js
import { call, put, takeEvery } from 'redux-saga/effects';
import axios from 'axios';
function* fetchUsersSaga() {
try {
// REST запрос ЗДЕСЬ
const response = yield call(axios.get, '/api/v1/users');
yield put({
type: 'USERS_SUCCESS',
payload: response.data
});
} catch (error) {
yield put({
type: 'USERS_ERROR',
payload: error.message
});
}
}
// Слушаем action
export function* userSaga() {
yield takeEvery('FETCH_USERS', fetchUsersSaga);
}
Современный подход: RTK Query (не Redux Thunk)
// api/usersApi.ts
import { createApi, fetchBaseQuery } from '@reduxjs/toolkit/query/react';
const usersApi = createApi({
reducerPath: 'usersApi',
baseQuery: fetchBaseQuery({ baseUrl: '/api/v1' }),
endpoints: (builder) => ({
getUsers: builder.query({
query: () => '/users' // REST запрос ЗДЕСЬ
}),
createUser: builder.mutation({
query: (userData) => ({
url: '/users',
method: 'POST',
body: userData
})
})
})
});
export const { useGetUsersQuery, useCreateUserMutation } = usersApi;
// В компоненте
function UserList() {
const { data: users, isLoading } = useGetUsersQuery();
// RTK Query автоматически управляет loading, caching, errors
}
TanStack Query / React Query (рекомендую)
// hooks/useUsers.ts
import { useQuery, useMutation } from '@tanstack/react-query';
import axios from 'axios';
const api = axios.create({ baseURL: '/api/v1' });
export function useGetUsers() {
return useQuery({
queryKey: ['users'],
queryFn: async () => {
// REST запрос ЗДЕСЬ
const response = await api.get('/users');
return response.data;
},
staleTime: 1000 * 60 * 5 // 5 minutes
});
}
export function useCreateUser() {
const queryClient = useQueryClient();
return useMutation({
mutationFn: async (userData) => {
// REST запрос ЗДЕСЬ
const response = await api.post('/users', userData);
return response.data;
},
// После успеха - invalidate кэш
onSuccess: () => {
queryClient.invalidateQueries({ queryKey: ['users'] });
}
});
}
// В компоненте
function UserList() {
const { data: users, isPending, error } = useGetUsers();
if (isPending) return <div>Loading...</div>;
if (error) return <div>Error: {error.message}</div>;
return (
<ul>
{users.map(user => <li key={user.id}>{user.name}</li>)}
</ul>
);
}
Правильная архитектура: слой для API
Никогда не делаю REST запросы прямо в компонентах. Всегда создаю отдельный слой:
// lib/api.ts
import axios from 'axios';
const api = axios.create({
baseURL: '/api/v1',
headers: {
'Content-Type': 'application/json'
}
});
// Add token to requests
api.interceptors.request.use(config => {
const token = localStorage.getItem('token');
if (token) {
config.headers.Authorization = `Bearer ${token}`;
}
return config;
});
export default api;
// api/users.ts
import api from '@/lib/api';
export const usersApi = {
getAll: () => api.get('/users'),
getById: (id: string) => api.get(`/users/${id}`),
create: (data: CreateUserInput) => api.post('/users', data),
update: (id: string, data: UpdateUserInput) => api.patch(`/users/${id}`, data),
delete: (id: string) => api.delete(`/users/${id}`)
};
// В экшене (Redux Thunk)
export const fetchUsers = () => async (dispatch) => {
try {
const response = await usersApi.getAll(); // ЗДЕСЬ используем
dispatch({ type: 'USERS_SUCCESS', payload: response.data });
} catch (error) {
dispatch({ type: 'USERS_ERROR', payload: error.message });
}
};
// ИЛИ с React Query
export function useGetUsers() {
return useQuery({
queryKey: ['users'],
queryFn: () => usersApi.getAll().then(r => r.data)
});
}
Сравнение подходов
// 1. Redux Thunk - простой старый способ
// Плюсы: простой, базовый
// Минусы: много boilerplate кода, управление ошибок
// 2. Redux Saga - для сложной логики
// Плюсы: powerful, можно cancel requests
// Минусы: сложнее учить, много boilerplate
// 3. RTK Query - встроенное в Redux Toolkit
// Плюсы: удобно, встроено
// Минусы: tied to Redux, меньше flexibility
// 4. TanStack Query (РЕКОМЕНДУЮ) - лучший для большинства
// Плюсы: лучшее API, автоматическое caching, обновления
// Минусы: еще одна зависимость
// 5. SWR (от Vercel) - альтернатива
// Плюсы: простой, встроен в Next.js
// Минусы: меньше features чем React Query
Anti-pattern: REST запрос в экшене без async
// ❌ НЕПРАВИЛЬНО
export const fetchUsers = () => {
const response = fetch('/api/users'); // ОШИБКА: не await!
return {
type: 'USERS_SUCCESS',
payload: response // undefined!
};
};
// ❌ НЕПРАВИЛЬНО - REST запрос в компоненте
function UserList() {
const [users, setUsers] = useState([]);
// ❌ Это плохо
const response = fetch('/api/users')
.then(r => r.json())
.then(data => setUsers(data));
return <ul>{users.map(...)}</ul>;
}
// ✅ ПРАВИЛЬНО
function UserList() {
const [users, setUsers] = useState([]);
useEffect(() => {
const loadUsers = async () => {
const response = await fetch('/api/users');
const data = await response.json();
setUsers(data);
};
loadUsers();
}, []); // useEffect!
return <ul>{users.map(...)}</ul>;
}
Моя рекомендация для 2026
// Используй TanStack Query + Axios
// lib/api.ts
import axios from 'axios';
import { useQueryClient } from '@tanstack/react-query';
export const api = axios.create({
baseURL: '/api/v1'
});
// hooks/useApi.ts
export function useApiQuery<T>(
queryKey: string[],
fn: () => Promise<T>
) {
return useQuery({ queryKey, queryFn: fn });
}
export function useApiMutation<T>(fn: (data: any) => Promise<T>) {
return useMutation({ mutationFn: fn });
}
// В компоненте - просто используй
const { data: users } = useApiQuery(['users'], () =>
api.get('/users').then(r => r.data)
);
Итоги
- Redux Thunk - для управления state
- TanStack Query - для HTTP запросов (РЕКОМЕНДУЮ)
- RTK Query - если уже используешь Redux
- Всегда через async - не sync запросы
- Отдельный слой для API - не в компонентах
- useEffect для запросов - не прямо в render
- Обработка ошибок - всегда try/catch
- Caching - очень важно для performance