Как реализовать React компонент с текстовым полем для запроса к API, отображением результатов, индикатором загрузки и обработкой ошибок?
APIReactиндикатор загрузкиобработка ошибокфронтенд разработка
Что проверяют
Учтёте ли вы отмену устаревших запросов и задержку ввода, а не только базовую логику.
Как отвечать
Ключевых требований пять: не слать запрос на каждую букву, отменять устаревший, показывать состояние загрузки и ошибки, различать пустой результат и отсутствие запроса.
function Search() {
const [query, setQuery] = useState("");
const [state, setState] = useState({ status: "idle", items: [], error: null });
useEffect(() => {
const text = query.trim();
if (!text) { setState({ status: "idle", items: [], error: null }); return; }
const controller = new AbortController();
const timer = setTimeout(async () => {
setState((s) => ({ ...s, status: "loading" }));
try {
const res = await fetch(`/api/search?q=${encodeURIComponent(text)}`, { signal: controller.signal });
if (!res.ok) throw new Error(`Сервер ответил ${res.status}`);
const items = await res.json();
setState({ status: "success", items, error: null });
} catch (e) {
if (e.name !== "AbortError") setState({ status: "error", items: [], error: e.message });
}
}, 300);
return () => { clearTimeout(timer); controller.abort(); };
}, [query]);
return (
<>
<input value={query} onChange={(e) => setQuery(e.target.value)} />
<div aria-live="polite">
{state.status === "loading" && <Spinner />}
{state.status === "error" && <p role="alert">{state.error}</p>}
{state.status === "success" && (state.items.length ? <List items={state.items} /> : <p>Ничего не найдено</p>)}
</div>
</>
);
}Что здесь важно объяснить:
- одно состояние вместо трёх флагов. Отдельные
loading,errorиdataдопускают противоречивые комбинации вроде «идёт загрузка и уже есть ошибка»; - очистка эффекта снимает таймер и отменяет запрос. Без отмены медленный ответ на старый запрос перезапишет свежий результат: порядок ответов не гарантирован;
- отмена не ошибка: прерванный запрос отфильтровывается по типу;
- пустой ввод не шлёт запрос и возвращает исходное состояние;
- доступность: область с оповещением и роль оповещения для ошибки.
Честная оговорка в конце: в реальном проекте это делают через TanStack Query, где отмена, кэш, повтор и дедупликация уже реализованы.
Где спотыкаются
Не отменяют предыдущий запрос и ловят гонку ответов.
Держат три независимых флага состояния.
Шлют запрос на каждое нажатие клавиши.
Не различают пустой результат и отсутствие запроса.