React

JSX: разметка, которая на самом деле JavaScript

Первое, что отталкивает в React новичка: HTML лежит прямо внутри JavaScript. Выглядит как нарушение всех правил, которым учили десять лет. Но через час работы происходит щелчок: это не HTML внутри JS, это JS, который только притворяется HTML. Любой тег - это вызов функции, любой блок в фигурных скобках - обычное выражение. И как только это понятно, разметка перестаёт быть отдельным языком и становится кодом, с которым работают все привычные инструменты.

  • Любой React-компонент в Meta, Netflix, Vercel написан на JSX - это де-факто способ описывать UI в экосистеме
  • TypeScript-вариант TSX даёт автодополнение и проверку типов прямо в разметке, чего обычные шаблоны не умеют
  • Vue и Svelte используют свои шаблоны, но и они поддерживают JSX как опцию - идея оказалась влиятельной
  • Сборщики (Vite, SWC, Babel) превращают JSX в обычные вызовы функций ещё до того, как код попадёт в браузер

Предварительные знания

  • Урок про модель React (UI = f(state))
  • JavaScript-выражения: тернарный оператор, логическое И (&&), метод map у массивов
  • Понимание разницы между выражением (возвращает значение) и инструкцией

Откуда взялся синтаксис JSX

JSX вырос из XHP - расширения PHP в Facebook, которое позволяло писать HTML-теги прямо в PHP-коде с защитой от XSS. Когда Джордан Уолк переносил идею в браузер, он сохранил тот же приём: разметка как часть языка, а не как строки. Намеренно было решено не делать JSX обязательным - технически можно писать React и без него, вызывая createElement руками. Но почти никто так не делает: JSX оказался настолько удобнее, что стал лицом всей библиотеки.

JSX - это вызовы функций под капотом

JSX не понимается браузером напрямую. Перед запуском сборщик (Vite, Babel или SWC) переписывает каждый тег в вызов функции. Тег превращается в элемент - лёгкий объект с типом, props и детьми. Именно эти объекты React потом сравнивает при reconciliation. Поэтому JSX это не шаблонизатор, а удобная запись для создания объектов.

Раз тег это объект, его можно положить в переменную, вернуть из функции, передать в массив. JSX-элемент - полноправное значение языка. Это отличает React от шаблонов вроде Handlebars, где разметка живёт в строках и недоступна инструментам кода.

Современный JSX-transform (с React 17) не требует импортировать React в каждый файл: сборщик сам подставляет нужную функцию из react/jsx-runtime. Поэтому в новом коде строки import React встречаются всё реже.

Во что превращается JSX-тег к моменту запуска в браузере?

Чем JSX отличается от HTML

Так как JSX это JavaScript, у него свои правила имён. Слово class зарезервировано в JS, поэтому CSS-класс задаётся как className. Атрибуты пишутся в camelCase: onClick, onChange, htmlFor, tabIndex. Все теги обязаны закрываться, включая одиночные: img и br пишутся как самозакрывающиеся.

HTMLJSXПочему
class="box"className="box"class - зарезервированное слово в JavaScript
onclick="..."onClick={...}Обработчики в camelCase, значение - функция, не строка
<br><br />Любой тег обязан закрываться
for="id"htmlFor="id"for - тоже ключевое слово в JS

Ещё одно правило: компонент возвращает один корневой элемент. Если нужно вернуть несколько соседних узлов без лишнего div в DOM, их оборачивают во Fragment - пустой тег <>...</>. Он группирует элементы, но сам в разметку не попадает.

Почему в JSX CSS-класс задаётся через className, а не class?

Выражения, условия и списки внутри JSX

В фигурных скобках можно вычислить любое JS-выражение и вставить его результат в разметку: переменную, вызов функции, обращение к свойству. Важное ограничение: внутри скобок живут именно выражения, а не инструкции. if и for туда не поставить - вместо них работают тернарный оператор и логическое И.

Список рендерится методом map: массив данных превращается в массив JSX-элементов. Каждому элементу списка нужен атрибут key - стабильный идентификатор, по которому React понимает, какой элемент к какому относится между перерисовками. Эта тема разобрана подробно в следующем уроке, но привычку ставить key стоит выработать сразу.

Распространённая ловушка с &&: если слева число 0, React отрендерит сам 0 на экране. Поэтому условие лучше делать булевым: items.length > 0 && ..., а не items.length && ...

Почему внутри фигурных скобок JSX нельзя написать обычный if?

Связь с другими темами

JSX - это кирпич. Дальше из него строят компоненты и динамику:

  • Компоненты и props — JSX-элементы группируются в компоненты, которые принимают данные через props
  • Списки и keys — Рендер массива данных через map - типичное использование выражений в JSX

Итог

  • JSX - это синтаксический сахар: каждый тег компилируется в вызов вроде createElement и в итоге становится обычным JavaScript-объектом
  • В фигурных скобках можно писать любое JS-выражение, но не инструкции (if, for) - для условий используют тернарник и &&
  • Отличия от HTML: атрибут class пишется как className, атрибуты в camelCase (onClick, htmlFor), теги обязаны закрываться
  • Компонент возвращает один корневой узел - несколько элементов оборачивают во Fragment (<>...</>)
  • Так как JSX это код, в нём работают типы (TSX), автодополнение и обычная отладка

Связанные уроки

  • rc-01-why-react — JSX - это конкретное воплощение идеи UI = f(state) из вводного урока
  • rc-03-components-props — JSX описывает один элемент, а компоненты собирают из этих элементов переиспользуемые блоки
  • rc-04-rendering-lists-keys — Списки через map и атрибут key - прямое продолжение выражений в JSX
JSX: разметка, которая на самом деле JavaScript

0

1

Войти