← Назад к вопросам
Как решишь задачу получения данных с Backend в два этапа?
2.0 Middle🔥 171 комментариев
#Soft Skills и рабочие процессы
Комментарии (1)
🐱
claude-haiku-4.5PrepBro AI2 апр. 2026 г.(ред.)
Ответ сгенерирован нейросетью и может содержать ошибки
Как решишь задачу получения данных с Backend в два этапа?
Понимание задачи
Двухэтапное получение данных — это паттерн, когда мы сначала загружаем быстро доступные данные (например, список), а потом загружаем детальную информацию. Это улучшает perceived performance и User Experience.
Подход 1: Sequential Requests (последовательные запросы)
Сначала загружаем список, потом детали:
// React Query / TanStack Query
function UserProfile({ userId }) {
// Этап 1: получаем базовые данные
const { data: user } = useQuery({
queryKey: ['user', userId],
queryFn: () => api.getUser(userId)
});
// Этап 2: получаем детали (зависит от этапа 1)
const { data: userDetails } = useQuery({
queryKey: ['userDetails', userId],
queryFn: () => api.getUserDetails(userId),
enabled: !!user // запускается только когда user загружен
});
if (!user || !userDetails) return <Spinner />;
return <div>Имя: {user.name}, Статус: {userDetails.status}</div>;
}
Подход 2: Параллельные запросы с Priority
Если этапы независимы, загружаем параллельно:
function Dashboard() {
// Оба запроса идут параллельно
const userQuery = useQuery({
queryKey: ['user'],
queryFn: api.getUser
});
const statsQuery = useQuery({
queryKey: ['stats'],
queryFn: api.getStats
});
// Показываем частичные данные
return (
<div>
{userQuery.data && <UserCard user={userQuery.data} />}
{statsQuery.data && <Stats data={statsQuery.data} />}
</div>
);
}
Подход 3: Стратегия "быстрые данные" + "полные данные"
Грузим сначала лайтовую версию, потом тяжелую:
function ProductList() {
// Этап 1: получаем список (быстро, 100KB)
const { data: products } = useQuery({
queryKey: ['products-lite'],
queryFn: () => api.getProducts({ fields: ['id', 'name', 'price'] })
});
// Этап 2: загружаем full data в фоне (медленнее, 1MB)
useQuery({
queryKey: ['products-full'],
queryFn: () => api.getProducts({ fields: ['*'] }),
staleTime: 5 * 60 * 1000
});
return (
<ul>
{products?.map(p => (
<li key={p.id}>{p.name} - {p.price}RUB</li>
))}
</ul>
);
}
Подход 4: Effector (State Management)
const $users = createStore([]);
const $userDetails = createStore({});
const getUsers = createEffect(async () => {
return await api.getUsers();
});
const getUserDetails = createEffect(async (userId) => {
return await api.getUserDetails(userId);
});
// Этап 1: загружаем пользователей
sample({
clock: getUsers.doneData,
target: $users
});
// Этап 2: когда пользователи загружены, загружаем первого
sample({
clock: $users,
filter: (users) => users.length > 0,
fn: (users) => users[0].id,
target: getUserDetails
});
sample({
clock: getUserDetails.doneData,
target: $userDetails
});
Подход 5: GraphQL (один запрос, структурированные данные)
const GET_USER_WITH_DETAILS = gql`
query GetUser($id: ID!) {
user(id: $id) {
id
name
# Lazy load детали
details {
bio
avatar
createdAt
}
}
}
`;
function UserProfile({ userId }) {
const { data, loading } = useQuery(GET_USER_WITH_DETAILS, {
variables: { id: userId }
});
return loading ? <Spinner /> : <div>{data.user.name}</div>;
}
Обработка ошибок и состояний
function SafeDataFetch({ userId }) {
const userQuery = useQuery({
queryKey: ['user', userId],
queryFn: api.getUser,
retry: 3 // повтори 3 раза
});
const detailsQuery = useQuery({
queryKey: ['details', userId],
queryFn: api.getDetails,
enabled: !!userQuery.data
});
if (userQuery.isLoading) return <Spinner />;
if (userQuery.error) return <Error msg={userQuery.error.message} />;
if (detailsQuery.error) return <ErrorBoundary />;
return <div>{userQuery.data.name}</div>;
}
Best Practices
- Показывай прогресс — не оставляй пользователя без обратной связи
- Кешируй данные — не переделывай запросы ненужно
- Обработай ошибки на каждом этапе — не падай с одной ошибки
- Используй skeleton loaders — показывай плейсхолдеры вместо спиннеров
- Отмени запросы при unmount — не утекай память
Заключение
Выбор подхода зависит от архитектуры:
- Sequential — когда второе зависит от первого
- Parallel — когда независимы
- Staggered — когда нужна быстрая feedback
- GraphQL — когда хочешь один запрос
Главное — всегда думать о UX: показывать прогресс, кешировать данные и правильно обрабатывать ошибки.