Главная / Статьи / React JSX похож на HTML — он компилируется в JavaScript.

React JSX похож на HTML — он компилируется в JavaScript.

JSX — это маркированный язык JavaScript: один корневой элемент, закрытые теги, атрибуты в формате camelCase и фигурные скобки для выражений — с классическими правилами, с которыми сталкиваются новички в первую очередь.

1208 слов

JSX выглядит как HTML в файле компонента, но он компилируется в JavaScript — и именно это объясняет почти все правила синтаксиса.

В предыдущих главах маркировка, возвращаемая компонентом — например <h1>Hello</h1> — часто называлась неформальным термином «маркировка». На самом деле её называют JSX. Цель здесь проста: рассматривать JSX как JavaScript, который случайно выглядит как HTML. Как только это становится ясным, большинство внешних правил синтаксиса перестают казаться произвольными.

Почему JSX — маркировка и логика вместе

В классическом фронтенде структура хранилась в файлах HTML, а поведение — в файлах JavaScript. На практике трудно разделить внешний вид кнопки и обработчик её нажатия. React объединяет и то, и другое в одной единице — компоненте, поэтому ему нужен способ записи маркировки внутри JavaScript. Именно этот синтаксис и называется JSX.

Визуально JSX похож на HTML. Поскольку компилятор преобразует JSX в JavaScript, правила здесь строже, чем в HTML. Начните с трех основных правил, которые помогут новичкам.

Три правила JSX

Правило 1 — один корень

Компонент может возвращать только один дерево JSX. Несколько элементов-братьев должны находиться под одним родителем.

// 🔴 two siblings side by side — error
return (
  <h1>Title</h1>
  <p>Content</p>
);

// ✅ wrapped in one
return (
  <div>
    <h1>Title</h1>
    <p>Content</p>
  </div>
);

Если дополнительный элемент <div> будет засорять DOM, оберните братьев в Fragment (<>...</>).

return (
  <>
    <h1>Title</h1>
    <p>Content</p>
  </>
);

Почему один корень? JSX превращается в значение JavaScript. Функция не может вернуть два значения одновременно без их упаковки; то же самое касается и JSX. Именно осознание того, что это JavaScript, а не HTML, делает это правило логичным.

Правило 2 — закрывайте каждый тег

В HTML некоторые теги, такие как <img> или <br>, могут использоваться без закрывающего тега. В JSX каждый тег должен быть закрыт. Теги без дочерних элементов используют формат самозакрывающегося тега />.

// 🔴 an HTML habit — error
<img src="logo.png">
<input type="text">

// ✅ self-closing
<img src="logo.png" />
<input type="text" />

Правило 3 — атрибуты в формате camelCase

Атрибуты JSX становятся ключами в объекте JavaScript, поэтому их названия должны соответствовать конвенциям JavaScript (camelCase), а не названиям из HTML. Часто возникают коллизии с зарезервированными словами:

  • class → className (class является зарезервированным словом в JavaScript)
  • for → htmlFor (for также является зарезервированным словом)
// 🔴 straight from HTML
<div class="card">
  <label for="email">Email</label>
</div>

// ✅ the JSX way
<div className="card">
  <label htmlFor="email">Email</label>
</div>

Та же самая логика преобразует onclick в onClick, а tabindex — в tabIndex. Нет необходимости запоминать полный список: функция автодополнения редактора и флаг TypeScript быстро исправляют неверные названия.

Круглые скобки {} — JavaScript внутри JSX

Именно здесь JSX перестаёт быть статической шаблонной системой. Поскольку JSX — это JavaScript, круглые скобки {} позволяют вставлять на их место значение JavaScript. HTML может содержать только фиксированный текст; JSX же способен оценивать выражения.

function Greeting() {
  const name = 'Jane';
  return <h1>Hello, {name}!</h1>; // inside the braces is JavaScript
}

{name} заменяется на значение переменной name ('Jane'). Скобки могут принимать любое выражение — код, который возвращает значение, а не только простые переменные.

function Bill() {
  const price = 12000;
  const count = 3;
  return (
    <div>
      <p>Unit price: {price} won</p>
      <p>Quantity: {count}</p>
      <p>Total: {price * count} won</p>          {/* arithmetic works too */}
      <p>{new Date().getFullYear()} receipt</p>  {/* function calls work too */}
    </div>
  );
}

Скобки также используются в значениях атрибутов. В этом случае кавычки вокруг скобок не требуются.

function Avatar() {
  const user = { name: 'Jane Kim', imageUrl: '/me.png' };
  return <img src={user.imageUrl} alt={user.name} />;
}
  • src="..." — кавычки означают буквальную строку.
  • src={...} — скобки означают значение JavaScript.

Разрешены только выражения

Внутри скобок можно размещать выражение, возвращающее значение. Нельзя использовать инструкции, такие как if, for или const.

// 🔴 an if statement isn't an expression, so this fails
<p>{if (count > 0) 'in stock'}</p>

// ✅ the ternary operator is an expression, so it works
<p>{count > 0 ? 'in stock' : 'out of stock'}</p>

Условный интерфейс с тернарными операторами, && и подобными конструкциями рассматривается в отдельной главе о условной отрисовке. На данный момент действует правило: внутрь круглых скобок могут помещаться только коды, возвращающие значение.

Двойные скобки {{ }} — объект внутри скобок

Шаблон {{ }}, часто встречающийся в JSX, не является отдельной особенностью языка. Это объект JavaScript { }, вложенный во внешние скобки. Типичным примером являются встроенные стили.

// outer { } = "I'm putting JavaScript here"
// inner { } = the object itself
<div style={{ color: 'tomato', fontSize: 20 }}>styled</div>

В HTML используется строка вроде style="color: tomato". В JSX передается объект, поэтому имена свойств пишутся в формате camelCase (fontSize вместо font-size), а значения обычно представляют собой строки или числа. Если двойные скобки кажутся неясными, сначала разделите их на переменную с именем.

const cardStyle = { color: 'tomato', fontSize: 20 };
<div style={cardStyle}>styled</div>   // exactly the same as above

Внешние скобки означают «вставить здесь значение JavaScript»; внутренний объект — это и есть то значение.

Как писать комментарии

Комментарии в JSX также используют скобки: это блоковый комментарий на JavaScript, заключенный в {}.

return (
  <div>
    {/* this is a comment inside JSX */}
    <h1>Title</h1>
  </div>
);

Собираем всё вместе

Вышеуказанные правила помещаются в один компонент карточки продукта.

// src/ProductCard.tsx
function ProductCard() {
  const product = {
    name: 'Mechanical Keyboard',
    price: 89000,
    inStock: true,
    imageUrl: "https://picsum.photos/200/300",
  };

  return (
    <div className="card" style={{ padding: 16 }}>
      {/* image: self-closing + brace attributes */}
      <img src={product.imageUrl} alt={product.name} />

      <h2>{product.name}</h2>
      <p>Price: {product.price.toLocaleString()} won</p>

      {/* show stock with an expression (ternary) — more in the next chapter */}
      <p>{product.inStock ? 'In stock' : 'Out of stock'}</p>
    </div>
  );
}

export default ProductCard;

В этом примере используются все три структурных правила (один корневой элемент, закрывающиеся теги, className) и все распространённые схемы скобок (вставка текста, атрибуты, арифметические операции, тернарные выражения, объекты стилей).

Итоги

  • JSX — это JavaScript, а не HTML, поэтому его синтаксис строже, чем у HTML.
  • Три структурных правила: объединять братьев в один корневой элемент (достаточно фрагмента), закрывать каждый тег и использовать атрибуты в формате camelCase (class→className, for→htmlFor).
  • Кривые скобки {} содержат выражение JavaScript, будь то в тексте или в атрибутах.
  • В скобки могут входить только выражения, возвращающие значение — не операторы вроде if или for.
  • {{ }} — это не новая синтаксис; это объект в круглых скобках. Примером могут служить встроенные стили.
  • Следующим логичным шагом является передача данных в компонент извне — с помощью props. Хардкодинг объекта product внутри компонента подходит только для демонстрации; с использованием props один и тот же ProductCard может отображать множество продуктов, и именно здесь типизация на TypeScript становится особенно важной.

    Ссылки

    • Документация React по использованию JSX
    • Документация React по встраиванию выражений