Компоненты позволяют разделить пользовательский интерфейс на самостоятельные, многоразовые фрагменты и подумать о каждой части отдельно.

Концептуально компоненты похожи на функции JavaScript. Они принимают произвольные входы (называемые «реквизиты») и возвращают элементы 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, которые представляют теги DOM:

const element = <div />;

Однако элементы также могут представлять пользовательские компоненты:

const element = <Welcome name="Sara" />;

Когда React видит элемент, представляющий пользовательский компонент, он передает атрибуты JSX этому компоненту как единый объект. Этот объект называется «реквизитом».

Например, этот код отображает «Hello, Sara» на странице:

function Welcome(props) {
  return <h1>Hello, {props.name}</h1>;
}

const element = <Welcome name="Sara" />;
ReactDOM.render(
  element,
  document.getElementById('root')
);

Напомним, что происходит в этом примере:

  1. Мы называем ReactDOM.render()с <Welcome name="Sara" /> элементом.
  2. Реакция вызывает <Welcome name="Sara" /> с помощью реквизита.
  3. В результате наш Welcome компонент возвращает <h1>Hello, Sara</h1> элемент.
  4. React DOM эффективно обновляет DOM для соответствия <h1>Hello, Sara</h1>.

Всегда начинайте имена компонентов с большой буквы.

React обрабатывает компоненты, начиная с строчных букв, как теги DOM. Например, <div />представляет собой тег div HTML, но <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 в существующее приложение, вы можете начать снизу вверх с помощью небольшого компонента, Button и постепенно подойдите к вершине иерархии представлений.

Извлечение компонентов

Не бойтесь разделить компоненты на более мелкие компоненты. Например, рассмотрим этот 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(object), text(string) и date(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 рядом с именем пользователя:

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), или достаточно сложна сама по себе (App, FeedStory, Comment), он является хорошим кандидатом быть многократно используемым компонентом.

Реквизиты доступны только для чтения

Независимо от того, объявляете ли вы компонент как функцию или класс , он никогда не должен изменять свои собственные реквизиты. Рассмотрим эту sum функцию:

function sum(a, b) {
  return a + b;
}

Такие функции называются «чистыми», потому что они не пытаются изменить свои входы и всегда возвращают один и тот же результат для одних и тех же входных данных.

Напротив, эта функция нечиста, потому что она меняет свой собственный вход:

function withdraw(account, amount) {
  account.total -= amount;
}

Реакция довольно гибкая, но имеет одно строгое правило:

Все компоненты React должны действовать как чистые функции в отношении своих реквизитов.