Таблица пользователей с фильтром по городу

Получите пользователей один раз, сформируйте список уникальных городов и фильтруйте строки по выбранному значению. Пустое значение select означает «Все».

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

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

Получите пользователей один раз, сформируйте список уникальных городов и фильтруйте строки по выбранному значению. Пустое значение select означает «Все».

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

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

Условие

Необходимо реализовать React‑компонент UserTable2, который выводит список пользователей в виде таблицы. Требования:

  • Получить массив пользователей с API https://jsonplaceholder.typicode.com/users.
  • Таблица должна содержать столбцы: ID, Имя, Email, Город.
  • Над таблицей разместить заголовок Список пользователей.
  • Добавить выпадающий список «Фильтр по городу». При выборе конкретного города в таблице отображаются только пользователи из этого города, а при выборе пункта Все – весь список.
const apiUrl = "https://jsonplaceholder.typicode.com/users";

const UserTable2 = () => {
  return <div></div>;
};

export default UserTable2;

Пример ожидаемого вида:

Список пользователей

[ Фильтр по городу: Все ▼ ]

ID Имя Email Город
1 Leanne Graham Sincere@april.biz Gwenborough
2 Ervin Howell Shanna@melissa.tv Wisokyburgh
3 Clementine Bauch Nathan@yesenia.net McKenziehaven
4 Patricia Lebsack Julianne.OConner@kory.org South Elvis
5 Chelsey Dietrich Lucio_Hettinger@annie.ca Roscoeview
6 Mrs. Dennis Schulist Karley_Dach@jasper.info South Christy
7 Kurtis Weissnat Telly.Hoeger@billy.biz Howemouth
8 Nicholas Runolfsdottir V Sherwood@rosamond.me Aliyaview
9 Glenna Reichert Chaim_McDermott@dana.io Bartholomebury
10 Clementina DuBuque Rey.Padberg@karina.biz Lebsackbury

Ответ

Получите пользователей один раз, сформируйте список уникальных городов и фильтруйте строки по выбранному значению. Пустое значение select означает «Все».

const apiUrl = 'https://jsonplaceholder.typicode.com/users';
const UserTable2 = () => {
  const [users, setUsers] = React.useState([]);
  const [city, setCity] = React.useState('');
  const [status, setStatus] = React.useState('loading');
  React.useEffect(() => {
    const controller = new AbortController();
    (async () => {
      try {
        const response = await fetch(apiUrl, { signal: controller.signal });
        if (!response.ok) throw new Error('HTTP');
        const data = await response.json();
        if (!Array.isArray(data) || data.some(user => !user || typeof user.address?.city !== 'string')) throw new Error('Формат');
        if (!controller.signal.aborted) { setUsers(data); setStatus('ready'); }
      } catch { if (!controller.signal.aborted) setStatus('error'); }
    })();
    return () => controller.abort();
  }, []);
  const cities = [...new Set(users.map(user => user.address.city))];
  const visible = users.filter(user => !city || user.address.city === city);
  return <section><h2>Список пользователей</h2>
    <label>Фильтр по городу <select value={city} onChange={e => setCity(e.target.value)}>
      <option value=''>Все</option>{cities.map(value => <option key={value} value={value}>{value}</option>)}
    </select></label>
    {status === 'loading' && <p>Загрузка…</p>}
    {status === 'error' && <p role='alert'>Не удалось загрузить пользователей</p>}
    <table><thead><tr>{['ID','Имя','Email','Город'].map(title => <th scope='col' key={title}>{title}</th>)}</tr></thead>
      <tbody>{visible.map(user => <tr key={user.id}><td>{user.id}</td><td>{user.name}</td><td>{user.email}</td><td>{user.address.city}</td></tr>)}</tbody>
    </table>
    {status === 'ready' && !visible.length && <p>Пользователей нет</p>}
  </section>;
};
export default UserTable2;

React импортируется в модуле. Переключение города не создаёт повторных сетевых запросов.

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

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

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

Подробнее