React JSX похож на HTML — он компилируется в JavaScript.
JSX — это маркированный язык JavaScript: один корневой элемент, закрытые теги, атрибуты в формате camelCase и фигурные скобки для выражений — с классическими правилами, с которыми сталкиваются новички в первую очередь.
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 по встраиванию выражений