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';
// Basic JSX - single root element
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.
// Original JSX
const element = <h1 className="title">Hello</h1>;
// After transpilation
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 и reconsilation, поэтому 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 года. Мы проконсультируем вас и предложим наилучшее решение.
Читайте также