> Как использовать useEffect и useState для загрузки и отображения данных в React (React)
Уровень: senior · Роль: frontend · Категория: Технические вопросы
Компании: Сбер
Стек: React
> Пример ответа
Короткий ответ
useState хранит данные и состояние загрузки, useEffect выполняет side effect - запрос к API. Внутри useEffect вызываем асинхронную функцию, устанавливаем loading=true, затем после ответа - data или error. Зависимости ([]) гарантируют однократный вызов при монтировании. Важно обрабатывать race condition через cleanup-функцию или AbortController.
Подробное объяснение
Основной паттерн - комбинация useState для трёх состояний (данные, загрузка, ошибка) и useEffect для выполнения запроса. useEffect с пустым массивом зависимостей запускается только при монтировании компонента. Внутри эффекта нельзя напрямую использовать async, поэтому создаём внутреннюю асинхронную функцию и вызываем её.
Ключевые моменты для senior-уровня:
- Race condition: при быстрых перемонтированиях ответ от предыдущего запроса может перезаписать актуальные данные. Решение -
AbortControllerили флагcancelled. - Cleanup: возвращаем функцию из
useEffect, которая отменяет запрос или сбрасывает флаг. - Зависимости: если запрос зависит от пропсов или стейта, добавляем их в массив зависимостей - эффект перезапускается при изменении.
- Обработка ошибок:
try/catchвнутри асинхронной функции, установкаerrorв стейт. - Оптимизация: для повторяющихся запросов - debounce, для кеширования - custom hook или библиотека (React Query, SWR).
На практике
В реальных проектах редко используют сырой useEffect для загрузки данных - обычно выносят логику в custom hook (например, useFetch). Это улучшает переиспользование и тестируемость. Для сложных сценариев (зависимые запросы, пагинация, optimistic updates) предпочтительнее React Query или SWR - они решают проблемы кеширования, ревалидации и race condition из коробки.
При реализации вручную важно:
- Не забывать про
AbortControllerдля отмены запросов при размонтировании. - Использовать
useCallbackдля функций, передаваемых в зависимости, чтобы избежать бесконечных циклов. - Для SSR (Next.js) использовать
getServerSidePropsилиuseEffectс проверкойtypeof window !== 'undefined'.
Пример кода
JSXimport { useState, useEffect } from 'react';function useFetch(url) {const [data, setData] = useState(null);const [loading, setLoading] = useState(true);const [error, setError] = useState(null);useEffect(() => {const abortController = new AbortController();let cancelled = false;async function fetchData() {setLoading(true);setError(null);try {const response = await fetch(url, { signal: abortController.signal });if (!response.ok) throw new Error(`HTTP ${response.status}`);const result = await response.json();if (!cancelled) setData(result);} catch (err) {if (err.name !== 'AbortError' && !cancelled) {setError(err.message);}} finally {if (!cancelled) setLoading(false);}}fetchData();return () => {cancelled = true;abortController.abort();};}, [url]);return { data, loading, error };}
Как отвечать на собеседовании
Начни с базового паттерна, затем сразу переходи к проблемам: race condition, cleanup, обработка ошибок. Покажи понимание, что в продакшене обычно используют готовые решения. Упомяни разницу между монтированием и обновлением зависимостей, объясни, почему нельзя делать useEffect(async () => ...). Приведи пример с AbortController - это показывает глубокое понимание.
Что проверяет интервьюер
- Понимание lifecycle React-компонентов и работы
useEffect. - Умение обрабатывать асинхронные операции и ошибки.
- Знание проблем многопоточности в однопоточном JS (race condition).
- Способность писать чистый, переиспользуемый код (custom hooks).
- Понимание trade-off между самописным решением и библиотеками.
Типичные ошибки
- Забывают про обработку ошибок и состояние
error. - Не используют cleanup, что приводит к утечкам памяти и race condition.
- Пытаются сделать
useEffectасинхронным напрямую. - Устанавливают
loadingтолько в начале, но не сбрасывают при ошибке. - Добавляют лишние зависимости в массив, вызывая бесконечные ререндеры.
- Не используют
AbortController, полагаясь только на флагcancelled.
> Похожие задачи по frontend
Какие глобальные state менеджеры существуют для React
Какие архитектурные паттерны используются в React
Корректно ли генерировать уникальный id для ключей в React при отсутствии id в данных с бэка и вызовет ли это проблемы с оптимизацией рендера
Есть ли проблемы при инициализации useState функцией в React и как их решить
> ГОТОВЫ К СЛЕДУЮЩЕМУ СОБЕСЕДОВАНИЮ?
Запустите тренировочную сессию с ИИ и получите детальную обратную связь, чтобы увереннее проходить реальные интервью