Создание автодополняющего Input‑компонента в React

Запрашивайте подсказки с небольшой задержкой после ввода, отменяйте предыдущий запрос и показывайте результаты через доступный список вариантов.

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

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

Запрашивайте подсказки с небольшой задержкой после ввода, отменяйте предыдущий запрос и показывайте результаты через доступный список вариантов.

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

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

Условие

В задании предоставлен API, возвращающий перечень персонажей из вселенной «Звёздных войн». Требуется написать React‑компонент InputAutocomplete, который будет предлагать варианты имен персонажей по мере ввода пользователем первых букв. При вводе часть строки, компонент должен показывать список подходящих подсказок, полученных через указанный API.

Описание API:

GET https://swapi.dev/api/people?search=skywalker&page=1
{
  next: string | null         // url
  results: Array({ name: string, url: string })  // max length 10, unique url
}

Исходный код проекта:

import React from 'react';

function getPeople(search, page = 1, options = {}) {
  return fetch(
    `https://swapi.dev/api/people?search=${search}&page=${page}`,
    options
  )
    .then((res) => res.json())
    .then((data) => data);
}

export default function App() {
  return 'Hello there!';
}

Ваша задача – реализовать компонент автодополнения, используя функцию getPeople для получения данных, и интегрировать его в приложение.

Ответ

Запрашивайте подсказки с небольшой задержкой после ввода, отменяйте предыдущий запрос и показывайте результаты через доступный список вариантов.

В getPeople добавьте кодирование параметров и проверку HTTP-ошибки:

async function getPeople(search, page = 1, options = {}) {
  const params = new URLSearchParams({ search, page: String(page) });
  const response = await fetch('https://swapi.dev/api/people?' + params, options);
  if (!response.ok) throw new Error('HTTP ' + response.status);
  return response.json();
}

Простой вариант с нативным datalist:

function InputAutocomplete() {
  const [query, setQuery] = React.useState('');
  const [items, setItems] = React.useState([]);
  const [status, setStatus] = React.useState('');
  const id = React.useId();
  React.useEffect(() => {
    const controller = new AbortController();
    setItems([]);
    if (!query.trim()) { setStatus(''); return; }
    setStatus('Загрузка…');
    const timer = setTimeout(async () => {
      try {
        const data = await getPeople(query.trim(), 1, { signal: controller.signal });
        if (!Array.isArray(data.results)) throw new Error('Формат');
        if (!controller.signal.aborted) { setItems(data.results); setStatus(data.results.length ? '' : 'Нет совпадений'); }
      } catch { if (!controller.signal.aborted) setStatus('Ошибка загрузки'); }
    }, 300);
    return () => { clearTimeout(timer); controller.abort(); };
  }, [query]);
  return <label>Персонаж
    <input list={id} value={query} onChange={e => setQuery(e.target.value)} />
    <datalist id={id}>{items.map(item => <option key={item.url} value={item.name} />)}</datalist>
    <span role='status'>{status}</span>
  </label>;
}
// В App: return <InputAutocomplete />;

Показаны первые 10 результатов по контракту API. Для полного списка добавляют загрузку следующей страницы по next; debounce не заменяет защиту от устаревшего ответа.

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

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

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

Подробнее