JSX Подробно
В основе JSX лежит синтаксический сахар для функции React.createElement(component, props, ...children). Код JSX:
<MyButton color="blue" shadowSize={2}>
Click Me
</MyButton> компилируется в:
React.createElement(
MyButton,
{color: 'blue', shadowSize: 2},
'Click Me'
) Также можно использовать сокращённую форму тега, если нет дочерних элементов. Таким образом:
<div className="sidebar" />
компилируется в:
React.createElement(
'div',
{className: 'sidebar'}
) Если вы хотите проверить, как определённый JSX преобразуется в JavaScript, вы можете воспользоваться онлайн-компилятором Babel.
Определение типа элемента React
Первая часть тега JSX определяет тип элемента React.
Использование прописных букв указывает на то, что тег JSX относится к компоненту React. Эти теги компилируются в прямую ссылку на именованную переменную, поэтому, если вы используете выражение JSX <Foo />, Foo должно быть в области видимости.
Библиотека React должна быть в области видимости
Так как JSX компилируется в вызовы React.createElement, библиотека React также должна быть в области видимости из вашего кода JSX.
Например, оба импорта необходимы в этом коде, даже если React и CustomButton не ссылаются напрямую из JavaScript:
import React from 'react';
import CustomButton from './CustomButton';
function WarningButton() {
// return React.createElement(CustomButton, {color: 'red'}, null);
return <CustomButton color="red" />;
} Если вы не используете пакетный менеджер JavaScript и загрузили React из тега <script>, он уже находится в области видимости как глобальная переменная React.
Использование точечной нотации для типа JSX
Вы также можете ссылаться на компонент React с помощью точечной нотации изнутри JSX. Это удобно, если у вас один модуль, экспортирующий множество компонентов React. Например, если MyComponents.DatePicker — это компонент, вы можете использовать его напрямую из JSX с помощью:
import React from 'react';
const MyComponents = {
DatePicker: function DatePicker(props) {
return <div>Imagine a {props.color} datepicker here.</div>;
}
}
function BlueDatePicker() {
return <MyComponents.DatePicker color="blue" />;
} Пользовательские компоненты должны начинаться с заглавной буквы
Когда тип элемента начинается с маленькой буквы, он относится к встроенному компоненту, например <div> или <span>, и результатом является строка 'div' или 'span', передаваемая в React.createElement. Типы, начинающиеся с заглавной буквы, например <Foo /> компилируются в React.createElement(Foo) и соответствуют компоненту, определённому или импортированному в ваш файл JavaScript.
Мы рекомендуем именовать компоненты с заглавной буквы. Если у вас есть компонент, начинающийся с маленькой буквы, назначьте ему переменную с заглавной буквы перед использованием в JSX.
Например, этот код не будет работать как ожидается:
import React from 'react';
// Wrong! This is a component and should have been capitalized:
function hello(props) {
// Correct! This use of <div> is legitimate because div is a valid HTML tag:
return <div>Hello {props.toWhat}</div>;
}
function HelloWorld() {
// Wrong! React thinks <hello /> is an HTML tag because it's not capitalized:
return <hello toWhat="World" />;
} Для исправления переименуйте hello в Hello и используйте <Hello /> при ссылке на него:
import React from 'react';
// Correct! This is a component and should be capitalized:
function Hello(props) {
// Correct! This use of <div> is legitimate because div is a valid HTML tag:
return <div>Hello {props.toWhat}</div>;
}
function HelloWorld() {
// Correct! React knows <Hello /> is a component because it's capitalized.
return <Hello toWhat="World" />;
} Выбор типа во время выполнения
Вы не можете использовать общее выражение в качестве типа элемента React. Если вы хотите использовать общее выражение для указания типа элемента, просто сначала назначьте его переменной с заглавной буквы. Это часто требуется, когда вы хотите отобразить другой компонент на основе свойства:
import React from 'react';
import { PhotoStory, VideoStory } from './stories';
const components = {
photo: PhotoStory,
video: VideoStory
};
function Story(props) {
// Wrong! JSX type can't be an expression.
return <components[props.storyType] story={props.story} />;
} Для исправления этого мы сначала назначим тип переменной с заглавной буквы:
import React from 'react';
import { PhotoStory, VideoStory } from './stories';
const components = {
photo: PhotoStory,
video: VideoStory
};
function Story(props) {
// Correct! JSX type can be a capitalized variable.
const SpecificStory = components[props.storyType];
return <SpecificStory story={props.story} />;
} Свойства в JSX
Существует несколько способов задания свойств в JSX.
Выражения JavaScript в качестве свойств
Вы можете передавать любые выражения JavaScript в качестве свойства, заключив их в {}. Например, в этом JSX:
<MyComponent foo={1 + 2 + 3 + 4} /> Для MyComponent, значение props.foo будет 10, так как выражение 1 + 2 + 3 + 4 вычисляется.
Инструкции if и циклы for не являются выражениями в JavaScript, поэтому их нельзя использовать напрямую в JSX. Вместо этого их можно поместить в окружающий код. Например:
function NumberDescriber(props) {
let description;
if (props.number % 2 == 0) {
description = <strong>even</strong>;
} else {
description = <i>odd</i>;
}
return <div>{props.number} is an {description} number</div>;
} Дополнительную информацию о условном отображении и циклах вы найдете в соответствующих разделах.
Строковые литералы
Вы можете передавать строковые литералы в качестве свойства. Эти два выражения JSX эквивалентны:
<MyComponent message="hello world" />
<MyComponent message={'hello world'} /> При передаче строкового литерала его значение не экранируется HTML. Таким образом, эти два выражения JSX эквивалентны:
<MyComponent message="<3" />
<MyComponent message={'<3'} /> Это поведение обычно неактуально. Оно упоминается здесь для полноты картины.
Свойства по умолчанию равны «True»
Если вы не передаёте значение для свойства, оно по умолчанию равно true. Эти два выражения JSX эквивалентны:
<MyTextBox autocomplete />
<MyTextBox autocomplete={true} /> В целом, не рекомендуется не передавать значение свойства, так как это может быть спутано с сокращённой записью ES6 {foo}, которая является сокращением от {foo: foo} а не от {foo: true}. Это поведение сохраняется для соответствия поведению HTML.
Распространение атрибутов
Если у вас уже есть props в виде объекта, и вы хотите передать его в JSX, вы можете использовать синтаксис «распространения» ... для передачи всего объекта свойств. Эти два компонента эквивалентны:
function App1() {
return <Greeting firstName="Ben" lastName="Hector" />;
}
function App2() {
const props = {firstName: 'Ben', lastName: 'Hector'};
return <Greeting {...props} />;
} Вы также можете выбрать определённые свойства, которые будет потреблять ваш компонент, передавая все остальные свойства с помощью синтаксиса распространения.
const Button = props => {
const { kind, ...other } = props;
const className = kind === "primary" ? "PrimaryButton" : "SecondaryButton";
return <button className={className} {...other} />;
};
const App = () => {
return (
<div>
<Button kind="primary" onClick={() => console.log("clicked!")}>
Hello World!
</Button>
</div>
);
}; В приведённом примере свойство kind безопасно потребляется и не передаётся элементу <button> в DOM. Все остальные свойства передаются через объект ...other, что делает этот компонент очень гибким. Вы можете увидеть, что он передаёт свойства onClick и children.
Распространение атрибутов может быть полезным, но оно также упрощает передачу ненужных свойств компонентам, которые ими не интересуются, или передачу недопустимых HTML-атрибутов в DOM. Мы рекомендуем использовать этот синтаксис экономно.
Дочерние элементы в JSX
В выражениях JSX, содержащих открывающий и закрывающий тег, содержимое между ними передаётся в качестве специального свойства: props.children. Существует несколько способов передачи дочерних элементов:
Строковые литералы
Вы можете поместить строку между открывающим и закрывающим тегами, и props.children будет просто этой строкой. Это полезно для многих встроенных HTML-элементов. Например:
<MyComponent>Hello world!</MyComponent>
Это допустимый JSX, и props.children в MyComponent будет просто строкой "Hello world!". HTML не экранируется, поэтому в этом случае вы можете написать JSX так же, как написали бы HTML:
<div>This is valid HTML & JSX at the same time.</div>
JSX удаляет пробелы в начале и конце строки. Также удаляются пустые строки. Переводы строк рядом с тегами удаляются; переносы строк внутри строковых литералов сводятся к одному пробелу. Поэтому все эти варианты отображаются одинаково:
<div>Hello World</div> <div> Hello World </div> <div> Hello World </div> <div> Hello World </div>
JSX Дочерние элементы
Вы можете предоставить больше элементов JSX в качестве дочерних элементов. Это полезно для отображения вложенных компонентов:
<MyContainer> <MyFirstComponent /> <MySecondComponent /> </MyContainer>
Вы можете смешивать различные типы дочерних элементов, поэтому вы можете использовать строковые литералы вместе с JSX дочерними элементами. Это ещё один способ, в котором JSX похож на HTML, поэтому это допустимый JSX и допустимый HTML:
<div>
Here is a list:
<ul>
<li>Item 1</li>
<li>Item 2</li>
</ul>
</div> Компонент React также может возвращать массив элементов:
render() {
// No need to wrap list items in an extra element!
return [
// Don't forget the keys :)
<li key="A">First item</li>,
<li key="B">Second item</li>,
<li key="C">Third item</li>,
];
} Выражения JavaScript в качестве дочерних элементов
Вы можете передавать любые выражения JavaScript в качестве дочерних элементов, заключив их в {}. Например, эти выражения эквивалентны:
<MyComponent>foo</MyComponent>
<MyComponent>{'foo'}</MyComponent> Это часто полезно для отображения списка выражений JSX произвольной длины. Например, это отображает HTML-список:
function Item(props) {
return <li>{props.message}</li>;
}
function TodoList() {
const todos = ['finish doc', 'submit pr', 'nag dan to review'];
return (
<ul>
{todos.map((message) => <Item key={message} message={message} />)}
</ul>
);
} Выражения JavaScript могут быть смешаны с другими типами дочерних элементов. Это часто бывает полезно вместо строковых шаблонов:
function Hello(props) {
return <div>Hello {props.addressee}!</div>;
} Функции в качестве дочерних элементов
Обычно выражения JavaScript, вставленные в JSX, будут вычисляться в строку, элемент React или список этих элементов. Однако props.children работает так же, как и любое другое свойство, то есть может передавать любые данные, а не только те, которые React может отобразить. Например, если у вас есть пользовательский компонент, вы можете указать обратный вызов в качестве props.children:
// Calls the children callback numTimes to produce a repeated component
function Repeat(props) {
let items = [];
for (let i = 0; i < props.numTimes; i++) {
items.push(props.children(i));
}
return <div>{items}</div>;
}
function ListOfTenThings() {
return (
<Repeat numTimes={10}>
{(index) => <div key={index}>This is item {index} in the list</div>}
</Repeat>
);
} Дочерние элементы, передаваемые в пользовательский компонент, могут быть любыми, пока этот компонент не преобразует их в нечто, что React может понять до отрисовки. Это использование не является распространённым, но работает, если вы хотите расширить возможности JSX.
Булевы значения, null и undefined игнорируются
false, null, undefined, и true являются допустимыми дочерними элементами. Они просто не отображаются. Эти выражения JSX будут отображаться одинаково:
<div />
<div></div>
<div>{false}</div>
<div>{null}</div>
<div>{undefined}</div>
<div>{true}</div> Это может быть полезно для условного отображения элементов React. Этот JSX отображает компонент <Header /> только если showHeader равно true:
<div>
{showHeader && <Header />}
<Content />
</div> Важное замечание заключается в том, что некоторые “ложные” значения, такие как число 0, всё ещё отображаются React. Например, этот код не будет работать так, как вы ожидаете, потому что 0 будет напечатано, когда props.messages пустой массив:
<div>
{props.messages.length &&
<MessageList messages={props.messages} />
}
</div> Для исправления этого убедитесь, что выражение перед && всегда булево:
<div>
{props.messages.length > 0 &&
<MessageList messages={props.messages} />
}
</div> И наоборот, если вы хотите, чтобы значение, такое как false, true, null, или undefined отображалось в выводе, вам нужно преобразовать его в строку сначала:
<div>
My JavaScript variable is {String(myVariable)}.
</div>
Полезная ли эта страница?
© 2013–present Facebook Inc.
Licensed under the Creative Commons Attribution 4.0 International Public License.
https://17.reactjs.org/docs/jsx-in-depth.html