Программирование с ИИ
ENRU
10.2

Компоненты и 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 &&.