Компоненты React позволяют разделить интерфейс на независимые, повторно используемые части, и думать о каждой части в отдельности.
Концептуально, компоненты похожи на функции JavaScript. Они принимают произвольные входные данные (так называемый «свойства») и возвращают React элементы, описывающие отображаемую на экране информацию.
Функциональные и классовые компоненты React
Простейший вариант определения компонента, запись его в виде JavaScript-функции:
function Welcome(props) {
return <h1>Hello, {props.name}</h1>;
}
Эта функция является допустимым React компонентом, поскольку она принимает как аргумент одно «свойство» объекта и возвращает React элемент. Мы называем такие компоненты «функциональными», потому что они в буквальном смысле функция JavaScript.
Также, для описания компонента можно использовать классы ES6 :
class Welcome extends React.Component {
render() {
return <h1>Hello, {this.props.name}</h1>;
}
}
Два вышеуказанных компонента эквивалентны с точки зрения React.
Классы имеют некоторые дополнительные возможности, которые мы рассмотрим в следующих разделах. До тех пор, мы будем использовать функциональные компоненты, поскольку они более лаконичны.
Отрисовка компонентов React
Раньше мы встречали только элементы React, которые представляют DOM теги:
const element = <div />;
Однако, элементы могут представлять компоненты созданные пользователем:
const element = <Welcome name="Sara" />;
Когда React видит элемент, представляющий собой определенный пользователем компонент, он передает JSX атрибуты данного компонента в качестве отдельного объекта. Мы называем этот объект «свойства» («props»).
Например, этот код выводит «Hello, Sara» на странице:
function Welcome(props) {
return <h1>Hello, {props.name}</h1>;
}
const element = <Welcome name="Sara" />;
ReactDOM.render(
element,
document.getElementById('root')
);
Давайте подведем итог, что мы узнали в этом примере:
- Мы вызываем ReactDOM.render() с элементом <Welcome имя = «Сара» /> .
- React вызывает компонент Welcome с аргументом {name: ‘Sara’} в качестве свойства .
- Наш компонент Welcome возвращает в качестве результата элемент <h1>Hello, Sara</h1>.
- React DOM эффективно обновляет DOM, чтобы соответствовать <h1>Hello, Sara</ h1>.
Предостережение:
Всегда начинайте составные имена с большой буквы.
Например, <div /> представляет собой DOM-тег, но <Welcome /> представляет собой компонент и требует записи Welcome, чтобы быть в области видимости
Композиция элементов
Компоненты могут ссылаться на другие компоненты при их выходе. Это позволяет нам использовать одну и ту же компонентную абстракцию для любого уровня детализации. Кнопка, форма, диалоговое окно, экран: в React-приложениях, все это оформляется в качестве компонентов.
Например, мы можем создать компонент App
, который отрисовывает (рендерит) компонент Welcome
многократно:
function Welcome(props) {
return <h1>Hello, {props.name}</h1>;
}
function App() {
return (
<div>
<Welcome name="Sara" />
<Welcome name="Cahal" />
<Welcome name="Edite" />
</div>
);
}
ReactDOM.render(
<App />,
document.getElementById('root')
);
Как правило, новые React приложения имеют один компонент App на самом верху иерархии. Тем не менее, если вы интегрируете React в существующее приложение, вы можете начать создавать иерархию компонентов снизу вверх, стартуя с небольшого компонента типа кнопки и постепенно подниматься к вершине иерархии представлений.
Предостережение:
Компоненты должны возвращать один корневой элемент. Именно поэтому мы добавили в <div>, все элементы
<Welcome />
.
Извлечение компонентов
Не бойтесь разделять компоненты на более мелкие компоненты.
Например, рассмотрим компонент Comment
:
function Comment(props) {
return (
<div className="Comment">
<div className="UserInfo">
<img className="Avatar"
src={props.author.avatarUrl}
alt={props.author.name}
/>
<div className="UserInfo-name">
{props.author.name}
</div>
</div>
<div className="Comment-text">
{props.text}
</div>
<div className="Comment-date">
{formatDate(props.date)}
</div>
</div>
);
}
Он принимает author
(как объект), text
(как строку) и date
(дату) как свойства и описывает комментарий на сайте.
Этот компонент может быть сложно изменить из-за всех вложенности, и затрудняет повторное использование отдельных частей. Давайте извлечем из него несколько компонентов.
Первым будет извлечен Avatar
:
function Avatar(props) {
return (
<img className="Avatar"
src={props.user.avatarUrl}
alt={props.user.name}
/>
);
}
Компоненту Avatar
не нужно знать, что он визуализируется внутри Comment
. Именно поэтому мы дали его свойству более общее название: user
(пользователь), а не author
(автор).
Мы рекомендуем присваивать названиям свойств компонентов, с точки зрения самого компонента, а не от контекста, в котором он используется.
Мы можем чуть-чуть упростить наш Comment
:
function Comment(props) {
return (
<div className="Comment">
<div className="UserInfo">
<Avatar user={props.author} />
<div className="UserInfo-name">
{props.author.name}
</div>
</div>
<div className="Comment-text">
{props.text}
</div>
<div className="Comment-date">
{formatDate(props.date)}
</div>
</div>
);
}
Следующим шагом, мы извлечем компонент UserInfo
, который отрисовывает Avatar
c следующим именем пользователя:
function UserInfo(props) {
return (
<div className="UserInfo">
<Avatar user={props.user} />
<div className="UserInfo-name">
{props.user.name}
</div>
</div>
);
}
Это позволит еще более упростить Comment
:
function Comment(props) {
return (
<div className="Comment">
<UserInfo user={props.author} />
<div className="Comment-text">
{props.text}
</div>
<div className="Comment-date">
{formatDate(props.date)}
</div>
</div>
);
}
Поначалу, извлечение компонентов может показаться тяжелой работой, но имея палитру повторно используемых компонентов мы окупим затраты удобством работы с большими приложениями. Возьмите за правило рассматривать в кандидаты компоненты, те части интерфейса, который используются несколько раз (Button
, Panel
, Avatar
), или разработанный самостоятельно UI (App
, FeedStory
, Comment
).
Свойства только на чтение
Если вы объявляете компонент в виде функции или класса, он никогда не должен изменять свои собственные реквизита. Рассмотрим эту функцию sum
:
function sum(a, b) {
return a + b;
}
Такие функции называются «чистыми» потому что не пытаются изменить свои аргументы и всегда возвращают один и тот же результат для одних и тех же аргументов.
В отличие от следующей функции, которая меняет введённый аргумент:
function withdraw(account, amount) {
account.total -= amount;
}
React довольно гибкая библиотека, но она имеет одно строгое правило:
Все React компоненты должны работать, как чистые функций по их свойствам.
Конечно, пользовательский интерфейс динамичен и меняется в разные фрагменты времени. В следующем разделе мы представим новую концепцию «состояния». Состояние позволяет React компонентам менять их отражение/отрисовку с течением времени в ответ на действия пользователя, сетевые ответы, не нарушая указанного выше правила.