JSX в деталях¶
JSX — синтаксический сахар для функции React.createElement(component, props, ...children)
. Этот JSX-код:
1 2 3 |
|
Скомпилируется в:
1 2 3 4 5 |
|
Вы также можете использовать самозакрывающийся тег, если отсутствуют дочерние элементы. Поэтому код:
1 |
|
Скомпилируется в:
1 |
|
Указание типа React-элемента¶
Первая часть JSX тега определяет тип React-элемента.
Типы, написанные с большой буквы, указывают, что JSX-тег ссылается на React-компонент. Эти теги компилируются в прямую ссылку на именованную переменную, поэтому, если вы используете JSX-выражение <Foo />
, то Foo
должен быть в области видимости.
React должен находиться в области видимости¶
Поскольку JSX компилируется в вызов React.createElement
, библиотека React
должна всегда быть в области видимости вашего JSX-кода.
К примеру, в данном коде оба импорта являются необходимыми, даже если на React
и CustomButton
нет прямых ссылок из JavaScript:
1 2 3 4 5 6 7 |
|
Если вы не используете сборщик JavaScript и загружаете React с помощью тега <script>
, то он уже доступен как React
в глобальной области видимости.
Использование записи через точку¶
Вы также можете ссылаться на React-компонент, используя запись через точку. Это удобно, если у вас есть модуль, который экспортирует много React-компонентов. К примеру, если MyComponents.DatePicker
является компонентом, то вы можете обратиться к нему напрямую, используя запись через точку:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
|
Названия типов пользовательских компонентов должны начинаться с большой буквы¶
Если название типа элемента начинается с маленькой буквы, он ссылается на встроенный компонент, к примеру <div>
или <span>
, что в результате приведёт к тому, что в React.createElement
будет передана строка 'div'
или 'span'
. Типы, начинающиеся с заглавной буквы, такие как <Foo />
, компилируются в React.createElement(Foo)
и соответствуют компоненту, который был объявлен или импортирован в вашем JavaScript-файле.
Мы рекомендуем называть компоненты с заглавной буквы. Если у вас есть компонент, название которого начинается с маленькой буквы, то перед тем как использовать его в JSX, присвойте его в переменную, которая имеет название с заглавной буквы.
К примеру, этот код будет работать не так, как ожидается:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
|
Для того, чтобы исправить это, мы переименуем hello
в Hello
и станем использовать <Hello />
, когда будем ссылаться на него:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
|
Выбор типа во время исполнения¶
В качестве типа React-элемента нельзя использовать выражение. Если вы хотите использовать выражение, чтобы указать тип элемента, присвойте его в переменную, начинающуюся с заглавной буквы. Это подходит для рендера компонентов в зависимости от ваших пропсов:
1 2 3 4 5 6 7 8 9 10 11 12 |
|
Чтобы исправить это, мы присвоим тип в переменную, начинающуюся с заглавной буквы:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
|
Пропсы в JSX¶
Существует несколько разных способов передачи пропсов в JSX.
JavaScript-выражения как пропсы¶
Вы можете передавать любые JavaScript-выражения как пропсы, обернув их в {}
. К примеру, в этом JSX:
1 |
|
Для MyComponent
значение props.foo
будет равно 10
, потому что выражение 1 + 2 + 3 + 4
будет вычислено.
Оператор if
и цикл for
не являются выражениями в JavaScript, поэтому их нельзя непосредственно использовать в JSX. Вместо этого, вы можете окружить ими JSX-код. К примеру:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
|
Вы можете узнать больше про условный рендеринг и циклы в соответствующих разделах.
Строковые литералы¶
Вы можете передать строковый литерал как проп. Эти два выражения эквивалентны:
1 2 3 |
|
Когда вы передаёте строковый литерал, все его возможные символы будут преобразованы в соответствующие HTML-сущности. Поэтому эти два JSX-выражения будут эквивалентны:
1 2 3 |
|
Обычно такое поведение не должно вас волновать. Оно упомянуто для полноты картины.
Установка пропсов по умолчанию в «true»¶
Если вы не передаёте значение в проп, то по умолчанию оно будет true
. Эти два JSX выражения эквивалентны:
1 2 3 |
|
В основном, мы не рекомендуем так делать, потому что это может быть воспринято как сокращение имён свойств из ES6. Тогда, например, {foo}
это короткая запись {foo: foo}
, но никак не {foo: true}
. Такое поведение существует для того, чтобы соответствовать поведению HTML.
Атрибуты расширения¶
Если у вас уже есть пропсы внутри объекта props
и вы хотите передать их в JSX, вы можете использовать оператор расширения ...
. Эти два компонента эквивалентны:
1 2 3 4 5 6 7 8 |
|
Вы так же можете выбрать конкретные пропсы, которые ваш компонент будет использовать, передавая все остальные пропсы с помощью оператора расширения.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
|
В приведённом выше примере, проп kind
используется безопасно и не передаётся в элемент <button>
, находящийся в DOM. Все остальные пропсы передаются с помощью объекта ...other
, что делает этот компонент очень гибким. Вы можете видеть, что он передаёт пропсы onClick
и children
.
Атрибуты расширения могут быть полезны, однако, также они позволяют передать ненужные пропсы в компоненты или невалидные HTML-атрибуты в DOM. Мы рекомендуем использовать этот синтаксис с осторожностью.
Дочерние компоненты в JSX¶
В JSX-выражениях содержимое, которое расположено между открывающими и закрывающими тегами, передаётся с помощью специального пропа: props.children
. Существует несколько способов передать дочерние компоненты:
Строковые литералы¶
Если вы поместите строку между открывающим и закрывающим тегом, то props.children
будет равно этой строке. Это полезно при создании встроенных HTML-элементов. К примеру:
1 |
|
Это корректный JSX-код, в котором значение props.children
в MyComponent
будет строкой "Привет, мир!"
. HTML не экранируется, поэтому JSX можно писать также как HTML:
1 |
|
JSX удаляет пустые строки и пробелы в начале и конце строки. Новые строки, примыкающие к тегу будут удалены. Новые строки между строковых литералов сжимаются в один пробел. Следующие три примера кода рендерят одинаковый результат:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
|
Дочерние JSX-компоненты¶
Чтобы отобразить вложенные компоненты, можно указать несколько JSX-элементов в качестве дочерних.
1 2 3 4 |
|
Вы можете смешивать различные типы потомков, скажем, использовать строковый литерал вместе с JSX-элементами. Вот ещё один пример, в котором JSX похож на HTML, причём данный код является валидным и для JSX, и для HTML:
1 2 3 4 5 6 7 |
|
Также React-компонент может возвращать массив элементов:
1 2 3 4 5 6 7 8 9 |
|
JavaScript-выражения как дочерние компоненты¶
Вы можете передать любое JavaScript-выражение как дочерний компонент, обернув его в {}
. К примеру, эти выражения эквивалентны:
1 2 3 |
|
Часто это бывает полезно при рендере списка JSX-выражений произвольной длины. Например, эта запись рендерит HTML-список:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
|
JavaScript-выражения могут быть использованы вместе с другими типами дочерних компонентов. Они могут рассматриваться как альтернатива шаблонным строкам:
1 2 3 |
|
Функции как дочерние компоненты¶
Обычно JavaScript-выражения, вставленные в JSX, будут приведены к строке, React-элементу или списку из всего этого. Тем не менее, props.children
работает так же, как и любой другой проп, поэтому в него можно передавать любые типы данных, а не только те, которые React знает как рендерить. К примеру, если у вас есть пользовательский компонент, можно было бы передать колбэк в props.children
:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
|
Дочерние компоненты, передаваемые пользовательскому компоненту, могут быть чем угодно с тем условием, что компонент преобразует их во что-то, что React сможет понять и отрендерить. Следующий пример редко встречается, но им можно воспользоваться, если необходимо расширить возможности JSX.
Логические значения, null и undefined игнорируются¶
Значения false
, null
, undefined
и true
— валидные дочерние компоненты. Просто они не рендерятся. Эти JSX-выражения будут рендерить одно и то же:
1 2 3 4 5 6 7 8 9 10 11 |
|
Этот подход может быть полезным для рендера по условию. Вот пример, где JSX рендерит <Header />
, если showHeader
равняется true
:
1 2 3 4 |
|
Есть один нюанс в том, что React будет рендерить «ложные» (falsy) значения, такие как число 0
. Код ниже ведёт себя не так, как вы могли ожидать, так как 0
будет отображён, если массив props.messages
пуст:
1 2 3 4 5 |
|
Чтобы исправить это, убедитесь что выражение перед оператором &&
всегда является boolean:
1 2 3 4 5 |
|
И наоборот, если вы хотите, чтобы такие значения как false
, true
, null
или undefined
отрисовались, то сначала вы должны преобразовать их в строку:
1 |
|