Получите пользователей один раз, сформируйте список уникальных городов и фильтруйте строки по выбранному значению. Пустое значение 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 | Имя | Город | |
|---|---|---|---|
| 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 импортируется в модуле. Переключение города не создаёт повторных сетевых запросов.