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.
- Три структурні правила: обгортати сестринські елементи в один кореневий елемент (достатньо Fragment), закривати кожен тег та використовувати атрибути у форматі camelCase (
class→className,for→htmlFor). - Криві дужки
{}містять вираз JavaScript, як у тексті, так і в атрибутах. - У дужки можуть потрапляти лише вирази, що генерують значення — а не оператори на кшталт
ifчиfor.
{{ }} — це не нова синтаксис; це об’єкт всередині дужок. Інлайн-стилі є класичним прикладом.Наступним логічним кроком є передача даних у компонент ззовні — через props. Хардкодування об’єкта product всередині компонента підходить для демонстрації; за допомогою props один і той самий ProductCard може відображати багато продуктів, і саме тут типування в TypeScript починає грати найважливішу роль.
Посилання
- Документація React про маркування з JSX
- Документація React про вбудовування виразів