Вторая задача: реализуйте компонент поиска с использованием стандартного сервера через query-параметр — сделайте input для ввода запроса, состояния для результатов и запроса, получение данных через fetch в useEffect с обработкой ошибок и состояния загрузки, отрисовку списка результатов (поле name).

Храните query и состояние запроса, кодируйте параметр URL и отменяйте предыдущий fetch при изменении ввода.

Короткий ответ

Что ответить на собеседовании

Храните query и состояние запроса, кодируйте параметр URL и отменяйте предыдущий fetch при изменении ввода.

Подробный разбор

Ответ с пояснениями

Храните query и состояние запроса, кодируйте параметр URL и отменяйте предыдущий fetch при изменении ввода.

Пример предполагает /api/search?q=... и массив объектов с уникальным id и строкой name:

import { useEffect, useState } from 'react';
export default function Search() {
  const [query, setQuery] = useState('');
  const [state, setState] = useState({ status: 'loading', data: [] });
  useEffect(() => {
    let active = true;
    const controller = new AbortController();
    setState({ status: 'loading', data: [] });
    async function load() {
      try {
        const res = await fetch('/api/search?' + new URLSearchParams({ q: query }),
          { signal: controller.signal });
        if (!res.ok) throw new Error('Request failed');
        const data = await res.json();
        if (!Array.isArray(data) || !data.every(x => x &&
          ['string', 'number'].includes(typeof x.id) && typeof x.name === 'string')) {
          throw new Error('Invalid response');
        }
        if (active) setState({ status: 'success', data });
      } catch {
        if (active && !controller.signal.aborted) setState({ status: 'error', data: [] });
      }
    }
    load();
    return () => { active = false; controller.abort(); };
  }, [query]);
  return <section>
    <label>Поиск <input value={query} onChange={e => setQuery(e.target.value)} /></label>
    {state.status === 'loading' && <p role="status">Загрузка...</p>}
    {state.status === 'error' && <p role="alert">Ошибка загрузки</p>}
    {state.status === 'success' && (state.data.length
      ? <ul>{state.data.map(x => <li key={x.id}>{x.name}</li>)}</ul>
      : <p>Ничего не найдено</p>)}
  </section>;
}

Debounce можно добавить отдельно; защита от устаревшего ответа нужна независимо от него.

ИИ-помощник для собеседований

Хочешь уверенно проходить собеседования?

Попробуй ИИ-помощник для собеседований: слышит вас и собеседника, анализирует экран, подсказывает ответы в реальном времени, работает без VPN и не попадает в захват экрана.

Подробнее