JSX — це XML-подібне розширення синтаксису JavaScript, розроблене командою React для декларативного опису користувацьких інтерфейсів. На відміну від шаблонізаторів, JSX компілюється у звичайні виклики JavaScript-функцій, що дає повну потужність мови всередині розмітки. За даними React, 2024, JSX підтримується у всіх сучасних React-фреймворках і бібліотеках.
Головне
JSX (JavaScript XML) — синтаксичне розширення для JavaScript, вперше представлене в React у 2013 році. Воно дозволяє розробникам описувати структуру користувацького інтерфейсу в декларативному стилі, поєднуючи розмітку та логіку в одному файлі.
До появи JSX розробники використовували рядкові шаблони (Mustache, Handlebars) або створювали DOM-елементи вручну через document.createElement. Обидва підходи мали недоліки: рядкові шаблони не перевірялися на типи, а ручне створення DOM було громіздким і схильним до помилок.
React обрав інший шлях — вбудовування розмітки прямо в код. Це рішення викликало суперечки в спільноті, але з часом стало стандартом. Сьогодні JSX використовується не лише в React, а й у SolidJS, Preact, Qwik і навіть у Vue через плагіни.
JSX-елемент виглядає як HTML-тег, але вбудовується безпосередньо в JavaScript. Кожен елемент транслюється у виклик React.createElement з трьома аргументами: тип елемента, об'єкт пропсів і дочірні елементи. Один кореневий елемент — обов'язкове правило: JSX-вираз має повертати один батьківський елемент або фрагмент.
import React from 'react';
// Базовий JSX — один кореневий елемент
const element = (
<div className="app">
<h1>Hello, World!</h1>
<p>Welcome to React</p>
</div>
);
Коли не потрібен зайвий DOM-вузол, використовуйте React.Fragment або короткий синтаксис <></>. Фрагменти не створюють справжнього DOM-елемента, а лише групують дочірні вузли. Це особливо корисно в таблицях і списках, де зайва обгортка порушила б HTML-структуру.
function Columns() {
return (
<>
<td>First</td>
<td>Second</td>
</>
);
}
Будь-який JavaScript-вираз вбудовується в JSX через фігурні дужки { }. Усередині можна використовувати змінні, виклики функцій, тернарні оператори та методи масивів. Умовний рендеринг виконується через тернарний оператор або логічне І.
function Greeting({ name, isLoggedIn }) {
const items = ['Red', 'Green', 'Blue'];
return (
<div>
{/* Expression with variable */}
<h1>Hello, {name}</h1>
{/* Conditional rendering */}
{isLoggedIn ?
<p>Welcome back!</p :
<button>Login</button>
}
{/* Render array */}
<ul>
{items.map(item =>
<li key={item}>{item}</li>
)}
</ul>
</div>
);
}
Ключове обмеження — усередині фігурних дужок можна використовувати лише вирази, не інструкції. Не можна використовувати if/else, for, switch — лише тернарний оператор, логічні оператори та методи масивів. Виклики функцій дозволені, зокрема стрілкові.
JSX візуально схожий на HTML, але має принципові відмінності. Атрибути пишуться в camelCase — className замість class, onClick замість onclick, tabIndex замість tabindex. Це пов'язано з тим, що JSX транслюється в JavaScript, де дефіс у назві властивості неприпустимий.
| HTML | JSX | Причина |
|---|---|---|
class="wrapper" | className="wrapper" | class — зарезервоване слово в JS |
onclick="handle()" | onClick={handle} | camelCase для JS-властивостей |
style="color: red" | style={{ color: 'red' }} | Об'єкт стилів замість рядка |
<input disabled> | <input disabled={true}> | Явне зазначення булевих атрибутів |
Ще одна важлива відмінність — самозакривні теги. В HTML деякі теги (br, hr, input) можуть бути незакритими. У JSX усі самозакривні теги зобов'язані мати закривний слеш: <br />, <input />. Імена SVG-атрибутів теж конвертуються в camelCase: strokeWidth, fillOpacity.
Браузери не розуміють JSX напряму. Перед виконанням JSX-код проходить через транспілятор — Babel, TypeScript або esbuild. Кожен JSX-елемент перетворюється на виклик createElement або jsx/runtime.
// Оригінальний JSX
const element = <h1 className="title">Hello</h1>;
// Після транспіляції
const element = React.createElement(
'h1',
{ className: 'title' },
'Hello'
);
З React 17 з'явилася нова JSX-трансформація, що не потребує імпорту React. Автоматичний імпорт jsx-runtime дозволяє писати компоненти без import React from 'react'. Babel і TypeScript підтримують цю трансформацію через налаштування {"runtime": "automatic"}.
Хоча JSX асоціюється з React, інші фреймворки також його використовують. SolidJS використовує JSX з компіляцією в реальні DOM-вузли, без Virtual DOM. Preact — легка альтернатива React з повною підтримкою JSX. Vue підтримує JSX через @vue/babel-plugin-jsx, хоча його основний шаблон — template.
Ключова відмінність — семантика виразів. У React JSX-вирази виконуються під час кожного рендеру. У SolidJS JSX компілюється один раз, а оновлення відстежуються через сигнали. Це впливає на продуктивність: SolidJS не потребує Virtual DOM і reconciliation, тому JSX-рендеринг швидший.
У TypeScript JSX підтримується на рівні мови. Файли з розширенням .tsx автоматично обробляють JSX-синтаксис. Типізація пропсів — одна з головних переваг TypeScript + JSX: IDE підказує очікувані атрибути, типи колбеків та обов'язковість пропсів.
Пишіть JSX-код, який легко читати та підтримувати. Виносьте складні вирази в окремі змінні або функції — це покращує читаність і дозволяє тестувати логіку окремо від розмітки. Використовуйте фрагменти замість зайвих div-обгорток.
Правило табуляції — дотримуйтеся відступів для вкладених елементів. Кожен рівень вкладеності — один рівень відступу. Закривний тег має бути на рівні відкривного. Для довгих атрибутів використовуйте перенесення рядка.
Уникайте inline-стрілкових функцій у пропсах, якщо вони створюються на кожен рендер. У таких випадках обгортайте колбек у useCallback або виносьте функцію за межі компонента. Розділяйте складні компоненти на дрібніші — кожен компонент має відповідати за одну логічну одиницю інтерфейсу.
Часті запитання
Так, через Babel-плагін @babel/plugin-transform-react-jsx можна налаштувати JSX для будь-якої бібліотеки. SolidJS, Preact, Nerv та інші фреймворки використовують JSX з власними runtime. Для повної незалежності можна вказати pragma на свою функцію.
class — зарезервоване слово в JavaScript. JSX транслюється в createElement, де другим аргументом передається об'єкт пропсів. Властивість class конфліктує з класовим синтаксисом ES6, тому React обрав className.
Використовуйте шаблонні рядки або бібліотеку classnames: className={`"btn ${isActive ? 'active' : ''}"`}. Для складної логіки підключіть npm-пакет clsx або classnames, які приймають об'єкти та масиви.
JSX підтримує лише вирази, не інструкції. Для умов використовуйте тернарний оператор, логічне І (&&) або логічне АБО (||). Для складної логіки виносьте умову в окрему змінну або функцію.
Атрибут key допомагає React ідентифікувати елементи списку під час ререндеру. Без key React перемальовує весь список при зміні. З унікальним key React перевикористовує DOM-вузли та перевпорядковує елементи, а не перестворює їх.
Підсумки
Ми розробимо мобільний застосунок під ключ
IT Sectr створює застосунки для iOS та Android для стартапів і бізнесу з 2017 року. Ми проконсультуємо вас і запропонуємо найкраще рішення.
Читайте також