Отображение данных с помощью пропсов

До этого момента, если бы вы повторно использовали компонент <Header />, он отображал бы одинаковый контент каждый раз.

index.html
function Header() {
  return <h1>Develop. Preview. Ship.</h1>;
}
 
function HomePage() {
  return (
    <div>
      <Header />
      <Header />
    </div>
  );
}

Но что, если вам нужно передать разный текст или информация заранее неизвестна, потому что вы получаете данные из внешнего источника?

Обычные HTML-элементы имеют атрибуты, которые можно использовать для передачи информации, изменяющей их поведение. Например, изменение атрибута src у элемента <img> меняет отображаемое изображение. Изменение атрибута href у тега <a> изменяет назначение ссылки.

Аналогичным образом, вы можете передавать информацию в виде свойств (пропсов) компонентам React. Например, возможные варианты кнопки:

Диаграмма, показывающая 3 варианта компонента кнопки: Primary, Secondary и Disabled

Подобно функции JavaScript, вы можете создавать компоненты, которые принимают пользовательские аргументы (или пропсы), изменяющие поведение компонента или его отображение на экране. Затем эти пропсы можно передавать от родительских компонентов к дочерним.

Примечание: В React данные передаются вниз по дереву компонентов. Это называется однонаправленным потоком данных. Состояние (state), которое будет рассмотрено в следующей главе, также может передаваться от родительских к дочерним компонентам в виде пропсов.

Использование пропсов

В компоненте HomePage вы можете передать пользовательский проп title в компонент Header, аналогично HTML-атрибутам:

index.html
function HomePage() {
  return (
    <div>
      <Header title="React" />
    </div>
  );
}

А компонент Header (дочерний) может принимать эти пропсы в качестве первого параметра функции:

index.html
function Header(props) {
  return <h1>Develop. Preview. Ship.</h1>;
}

Если вы вызовете console.log(props), то увидите, что это объект со свойством title.

index.html
function Header(props) {
  console.log(props); // { title: "React" }
  return <h1>Develop. Preview. Ship.</h1>;
}

Поскольку props — это объект, вы можете использовать деструктуризацию объектов для явного указания значений пропсов в параметрах функции:

index.html
function Header({ title }) {
  console.log(title); // "React"
  return <h1>Develop. Preview. Ship.</h1>;
}

Затем вы можете заменить содержимое тега <h1> своей переменной title.

index.html
function Header({ title }) {
  console.log(title);
  return <h1>title</h1>;
}

Если вы откроете файл в браузере, то увидите, что отображается само слово "title". Это происходит потому, что React считает, что вы хотите вывести обычную текстовую строку в DOM.

Вам нужно указать React, что это переменная JavaScript.

Использование переменных в JSX

Чтобы использовать проп title, добавьте фигурные скобки {}. Это специальный синтаксис JSX, позволяющий писать обычный JavaScript прямо внутри JSX-разметки.

index.html
function Header({ title }) {
  console.log(title);
  return <h1>{title}</h1>;
}

Фигурные скобки можно рассматривать как способ перехода в "режим JavaScript" внутри "режима JSX". Внутри фигурных скобок можно использовать любое выражение JavaScript (что-то, что вычисляется в одно значение). Например:

  1. Свойство объекта с точечной нотацией:
example.js
function Header(props) {
  return <h1>{props.title}</h1>;
}
  1. Шаблонную строку:
example.js
function Header({ title }) {
  return <h1>{`Cool ${title}`}</h1>;
}
  1. Возвращаемое значение функции:
example.js
function createTitle(title) {
  if (title) {
    return title;
  } else {
    return 'Default title';
  }
}
 
function Header({ title }) {
  return <h1>{createTitle(title)}</h1>;
}
  1. Или тернарный оператор:
example.js
function Header({ title }) {
  return <h1>{title ? title : 'Default Title'}</h1>;
}

Теперь вы можете передавать любую строку в проп title или, если использовали тернарный оператор, вообще не передавать проп title, так как предусмотрели случай по умолчанию в компоненте:

example.js
function Header({ title }) {
  return <h1>{title ? title : 'Default title'}</h1>;
}
 
function HomePage() {
  return (
    <div>
      <Header />
    </div>
  );
}

Теперь ваш компонент принимает универсальный проп title, который можно повторно использовать в разных частях приложения. Достаточно просто изменить строку title:

index.html
function HomePage() {
  return (
    <div>
      <Header title="React" />
      <Header title="A new title" />
    </div>
  );
}

Итерация по спискам

Часто бывает необходимо отобразить данные в виде списка. Вы можете использовать методы массивов для обработки данных и создания UI-элементов с одинаковым стилем, но разным содержимым.

Добавьте следующий массив имен в компонент HomePage:

index.html
function HomePage() {
  const names = ['Ada Lovelace', 'Grace Hopper', 'Margaret Hamilton'];
 
  return (
    <div>
      <Header title="Develop. Preview. Ship." />
      <ul>
        {names.map((name) => (
          <li>{name}</li>
        ))}
      </ul>
    </div>
  );
}

Затем можно использовать метод array.map() для перебора массива и стрелочную функцию для преобразования каждого имени в элемент списка:

index.html
function HomePage() {
  const names = ['Ada Lovelace', 'Grace Hopper', 'Margaret Hamilton'];
 
  return (
    <div>
      <Header title="Develop. Preview. Ship." />
      <ul>
        {names.map((name) => (
          <li>{name}</li>
        ))}
      </ul>
    </div>
  );
}

Обратите внимание, как фигурные скобки позволяют переключаться между "JavaScript" и "JSX".

Если запустить этот код, React выдаст предупреждение об отсутствии пропа key. Это потому, что React нужен уникальный идентификатор для элементов массива, чтобы понимать, какие элементы нужно обновлять в DOM.

Пока можно использовать имена, так как они уникальны, но рекомендуется использовать гарантированно уникальные значения, например ID элемента.

index.html
function HomePage() {
  const names = ['Ada Lovelace', 'Grace Hopper', 'Margaret Hamilton'];
 
  return (
    <div>
      <Header title="Develop. Preview. Ship." />
      <ul>
        {names.map((name) => (
          <li key={name}>{name}</li>
        ))}
      </ul>
    </div>
  );
}

Дополнительные ресурсы: