Компоненты и JSX
разметка внутри кода
Что это
Компонент — функция, которая возвращает разметку. Это вся идея React: вместо того чтобы менять страницу командами, ты описываешь, как она должна выглядеть при данных данных, а React сам приводит её к этому виду.
JSX — синтаксис, который позволяет писать разметку прямо в коде. Выглядит как HTML, но это JavaScript.
Как выглядит в коде
interface CityCardProps {
name: string;
temp: number | null;
onRemove: (name: string) => void;
}
export function CityCard({ name, temp, onRemove }: CityCardProps) {
return (
<article className="card">
<h2>{name}</h2>
<p>{temp === null ? "нет данных" : `${temp > 0 ? "+" : ""}${temp}°`}</p>
<button type="button" onClick={() => onRemove(name)}>Удалить</button>
</article>
);
}Что из этого получается — настоящий вывод:
<article class="card"><h2>Oslo</h2><p>+4°</p>
<button type="button">Удалить</button></article>
<article class="card"><h2>Tromsø</h2><p>нет данных</p>
<button type="button">Удалить</button></article>И как это выглядит на экране:

Как это читать
Компонент — функция с заглавной буквы. Это не стиль, а требование: с маленькой буквы React сочтёт его обычным тегом.
{ } внутри разметки — это выход в JavaScript. Всё, что в фигурных
скобках, вычисляется: {name}, {temp === null ? ... : ...},
{() => onRemove(name)}.
className вместо class. class — зарезервированное слово в
JavaScript. Так же htmlFor вместо for.
Возвращается один элемент. Два корневых рядом — ошибка. Если нужно, их
оборачивают в пустой тег <>...</>.
Деструктуризация в аргументе. ({ name, temp, onRemove }: CityCardProps)
— это «взять из объекта пропсов три поля». Эквивалент
(props: CityCardProps) и дальше props.name.
Списки и key
<div className="list">
{cities.map(c => <CityCard key={c.name} {...c} onRemove={handleRemove} />)}
</div>map вместо цикла. В JSX нельзя написать for — вместо этого массив
данных превращают в массив элементов.
key обязателен. Это не формальность: по нему React понимает, какой
элемент какой, когда список меняется. Без key при удалении из середины
списка данные «съезжают» на соседей. React предупреждает об этом в консоли
(статья 8.4).
key должен быть стабильным. Идентификатор записи — хорошо. Индекс
массива — плохо: при сортировке и удалении он меняется, и смысл теряется.
{...c} — расстановка. Передать все поля объекта как пропсы. Коротко,
но прячет, что именно передаётся: читающему приходится идти смотреть, из чего
состоит c.
Условия в разметке
{temp === null ? <p>нет данных</p> : <p>{temp}°</p>} // если-иначе
{isLoading && <Spinner />} // только если
{items.length > 0 && <List items={items} />} // осторожно!Третья строка — распространённая ловушка. Если items.length равен нулю,
на экране появится «0»: ноль не отображается как «ничего», а выводится как
число. Безопасно — items.length > 0 && (как здесь) или тернарный оператор.
Как сказать ИИ
Сделай компонент CityCard: принимает name (строка),
temp (число или null) и onRemove (функция от названия).
Если temp null — показывать «нет данных».
Типы пропсов отдельным интерфейсом, экспортировать его.Этот список рисуется через map без key. Добавь key
по идентификатору записи, не по индексу, и объясни почему.Разбей этот компонент на три поменьше. Логику не меняй,
только структуру. Покажи, какие пропсы у каждого.На что смотреть
Нет key или key={index}. Самая частая ошибка в сгенерированных списках.
{items.length && ...}. Покажет «0» вместо ничего.
Компонент на двести строк. Разбивается на части — иначе ни прочитать, ни переиспользовать.
Логика внутри разметки. Три вложенных тернарных оператора в JSX читаются тяжело. Вычисления выносятся выше, в переменные.
{...props} везде. Удобно писать, трудно читать: непонятно, что
передаётся.
Разметка без семантики. Всё те же div вместо button и article
(статья 8.2) — React этого не исправляет.
Шпаргалка
Компонент — функция с заглавной буквы, возвращает разметку.
{ }в JSX — выход в JavaScript;classNameвместоclass.Возвращается один корневой элемент, иначе оборачивай в
<>…</>.Списки через
map,keyобязателен и должен быть стабильным.key={index}ломается при сортировке и удалении.{x.length && ...}выведет «0». Пишиx.length > 0 &&.