HOW TO React

Условный рендеринг

Вашим компонентам часто приходится отображать разные элементы в зависимости от различных условий. В React можно выполнять условный рендеринг JSX с помощью синтаксиса JavaScript, такого как операторы if, && и ?:.

Вы узнаете

  • Как возвращать разный JSX в зависимости от условия
  • Как условно включать или исключать фрагмент JSX
  • Распространенные синтаксические сокращения для условий, с которыми вы столкнетесь в кодовой базе React

Условное возвращение JSX

Предположим, у вас есть компонент PackingList, отображающий несколько элементов Item, которые могут быть помечены как упакованные или нет:

function Item({ name, isPacked }) {  return <li className="item">{name}</li>;}export default function PackingList() {  return (    <section>      <h1>Sally Ride's Packing List</h1>      <ul>        <Item          isPacked={true}          name="Space suit"        />        <Item          isPacked={true}          name="Helmet with a golden leaf"        />        <Item          isPacked={false}          name="Photo of Tam"        />      </ul>    </section>  );}
Preview

Обратите внимание, что у некоторых компонентов Item свойство isPacked установлено в true, а не в false. Вы хотите добавить галочку (✅) к упакованным предметам, если isPacked={true}.

Вы можете написать это в виде if/else-выражения следующим образом:

if (isPacked) {
  return <li className="item">{name} ✅</li>;
}
return <li className="item">{name}</li>;

Если проп isPacked равен true, этот код возвращает другое дерево JSX. Благодаря этому изменению некоторые элементы получают галочку в конце:

function Item({ name, isPacked }) {  if (isPacked) {    return <li className="item">{name} ✅</li>;  }  return <li className="item">{name}</li>;}export default function PackingList() {  return (    <section>      <h1>Sally Ride's Packing List</h1>      <ul>        <Item          isPacked={true}          name="Space suit"        />        <Item          isPacked={true}          name="Helmet with a golden leaf"        />        <Item          isPacked={false}          name="Photo of Tam"        />      </ul>    </section>  );}
Preview

Попробуйте изменить то, что возвращается в каждом из случаев, и посмотрите, как изменится результат!

Обратите внимание, как вы создаете логику ветвления с помощью операторов if и return в JavaScript. В React управление потоком (например, условия) обрабатывается JavaScript.

Условное возвращение null

В некоторых ситуациях вам не захочется отображать ничего вообще. Например, предположим, вы не хотите показывать упакованные предметы. Компонент должен что-то возвращать. В этом случае вы можете вернуть null:

if (isPacked) {
  return null;
}
return <li className="item">{name}</li>;

Если isPacked равно true, компонент не вернет ничего, то есть null. В противном случае он вернет JSX для рендеринга.

function Item({ name, isPacked }) {  if (isPacked) {    return null;  }  return <li className="item">{name}</li>;}export default function PackingList() {  return (    <section>      <h1>Sally Ride's Packing List</h1>      <ul>        <Item          isPacked={true}          name="Space suit"        />        <Item          isPacked={true}          name="Helmet with a golden leaf"        />        <Item          isPacked={false}          name="Photo of Tam"        />      </ul>    </section>  );}
Preview

На практике возвращение null из компонента не является обычной практикой, так как это может удивить разработчика, пытающегося его отобразить. Чаще всего вы будете условно включать или исключать компонент в JSX родительского компонента. Вот как это сделать!

Условное включение JSX

В предыдущем примере вы контролировали, какое (если вообще какое-либо!) дерево JSX будет возвращено компонентом. Возможно, вы уже заметили некоторое дублирование в выводе рендеринга:

<li className="item">{name} ✅</li>

очень похоже на

<li className="item">{name}</li>

Обе условные ветви возвращают <li className="item">...</li>:

if (isPacked) {
  return <li className="item">{name} ✅</li>;
}
return <li className="item">{name}</li>;

Хотя это дублирование не наносит вреда, оно может затруднить поддержку вашего кода. Что, если вы захотите изменить className? Вам придется делать это в двух местах в коде! В такой ситуации вы можете условно включить небольшой фрагмент JSX, чтобы сделать ваш код более DRY.

Условный (тернарный) оператор (? :)

В JavaScript есть компактный синтаксис для написания условного выражения — условный оператор или 'тернарный оператор'.

Вместо этого:

if (isPacked) {
  return <li className="item">{name} ✅</li>;
}
return <li className="item">{name}</li>;

Вы можете написать так:

return (
  <li className="item">
    {isPacked ? name + ' ✅' : name}
  </li>
);

Это можно прочитать как 'если isPacked равно true, то (?) отобразить name + ' ✅', в противном случае (:) отобразить name'.

Являются ли эти два примера полностью эквивалентными?

Если у вас есть опыт объектно-ориентированного программирования, вы можете предположить, что два приведенных выше примера слегка различаются, поскольку один из них может создавать два разных 'экземпляра' <li>. Но элементы JSX не являются 'экземплярами', поскольку они не содержат внутреннего состояния и не являются реальными узлами DOM. Это лёгкие описания, подобные чертежам. Поэтому эти два примера, на самом деле, являются полностью эквивалентными. В разделе Сохранение и сброс состояния подробно описано, как это работает.

Теперь предположим, что вы хотите обернуть текст завершенного элемента в другой HTML-тег, например <del>, чтобы зачеркнуть его. Вы можете добавить еще больше новых строк и скобок, чтобы было проще вложить больше JSX в каждый из случаев:

function Item({ name, isPacked }) {  return (    <li className="item">      {isPacked ? (        <del>          {name + ' ✅'}        </del>      ) : (        name      )}    </li>  );}export default function PackingList() {  return (    <section>      <h1>Sally Ride's Packing List</h1>      <ul>        <Item          isPacked={true}          name="Space suit"        />        <Item          isPacked={true}          name="Helmet with a golden leaf"        />        <Item          isPacked={false}          name="Photo of Tam"        />      </ul>    </section>  );}
Preview

Этот стиль хорошо подходит для простых условий, но используйте его с умеренностью. Если ваши компоненты становятся запутанными из-за слишком большого количества вложенных условных разметки, подумайте о выделении дочерних компонентов, чтобы привести код в порядок. В React разметка является частью вашего кода, поэтому вы можете использовать такие инструменты, как переменные и функции, для упорядочивания сложных выражений.

Логический оператор AND (&&)

Еще одним распространенным сокращением, с которым вы столкнетесь, является логический оператор AND (&&) в JavaScript. Внутри компонентов React он часто используется, когда вы хотите отобразить какой-либо JSX, если условие истинно, *или не отображать ничего в противном случае. * С помощью && вы можете условно отобразить галочку только в том случае, если isPacked равно true:

return (
  <li className="item">
    {name} {isPacked && '✅'}
  </li>
);

Это можно прочитать как 'если isPacked, то (&&) отобразить галочку, в противном случае ничего не отображать'.

Вот как это работает:

function Item({ name, isPacked }) {  return (    <li className="item">      {name} {isPacked && '✅'}    </li>  );}export default function PackingList() {  return (    <section>      <h1>Sally Ride's Packing List</h1>      <ul>        <Item          isPacked={true}          name="Space suit"        />        <Item          isPacked={true}          name="Helmet with a golden leaf"        />        <Item          isPacked={false}          name="Photo of Tam"        />      </ul>    </section>  );}
Preview

Выражение JavaScript && возвращает значение правой части (в нашем случае галочку), если левая часть (наше условие) равна true. Но если условие равно false, все выражение становится false. React рассматривает false как 'дыру' в дереве JSX, точно так же, как null или undefined, и ничего не рендерит на его месте.

Не помещайте числа в левую часть &&.

Чтобы проверить условие, JavaScript автоматически преобразует левую часть в булево значение. Однако, если левая часть равна 0, то все выражение получает это значение (0), и React с удовольствием отобразит 0, а не ничего.

Например, распространенной ошибкой является написание кода типа messageCount && <p>New messages</p>. Легко предположить, что он ничего не отображает, когда messageCount равен 0, но на самом деле он отображает само число 0!

Чтобы исправить это, сделайте левую часть булевым значением: messageCount > 0 && <p>New messages</p>.

Условное присвоение JSX переменной

Когда сокращения мешают писать простой код, попробуйте использовать оператор if и переменную. Вы можете переназначить переменные, определенные с помощью let, поэтому начните с указания содержимого по умолчанию, которое вы хотите отобразить, — имени:

let itemContent = name;

Используйте оператор if, чтобы переназначить выражение JSX в itemContent, если isPacked равно true:

if (isPacked) {
  itemContent = name + ' ✅';
}

Фигурные скобки открывают 'окно в мир JavaScript'. Встройте переменную с фигурными скобками в возвращаемое дерево JSX, вложив ранее вычисленное выражение внутрь JSX:

<li className="item">
  {itemContent}
</li>

Этот стиль является самым развернутым, но также и самым гибким. Вот как он работает:

function Item({ name, isPacked }) {  let itemContent = name;  if (isPacked) {    itemContent = name + " ✅";  }  return (    <li className="item">      {itemContent}    </li>  );}export default function PackingList() {  return (    <section>      <h1>Sally Ride's Packing List</h1>      <ul>        <Item          isPacked={true}          name="Space suit"        />        <Item          isPacked={true}          name="Helmet with a golden leaf"        />        <Item          isPacked={false}          name="Photo of Tam"        />      </ul>    </section>  );}
Preview

Как и раньше, это работает не только с текстом, но и с произвольным JSX:

function Item({ name, isPacked }) {  let itemContent = name;  if (isPacked) {    itemContent = (      <del>        {name + " ✅"}      </del>    );  }  return (    <li className="item">      {itemContent}    </li>  );}export default function PackingList() {  return (    <section>      <h1>Sally Ride's Packing List</h1>      <ul>        <Item          isPacked={true}          name="Space suit"        />        <Item          isPacked={true}          name="Helmet with a golden leaf"        />        <Item          isPacked={false}          name="Photo of Tam"        />      </ul>    </section>  );}
Preview

Если вы не знакомы с JavaScript, такое разнообразие стилей сначала может показаться сложным. Однако их изучение поможет вам читать и писать любой код JavaScript — а не только компоненты React! Для начала выберите тот, который вам больше нравится, а затем обратитесь к этому справочнику снова, если забудете, как работают остальные.

Вывод

  • В React вы управляете логикой ветвления с помощью JavaScript.
  • Вы можете возвращать выражение JSX условно с помощью оператора if.
  • Вы можете условно сохранить часть JSX в переменной, а затем включить её в другой JSX, используя фигурные скобки.
  • В JSX {cond ? <A /> : <B />} означает 'если cond, отобразить <A />, иначе <B />'.
  • В JSX {cond && <A />} означает 'если cond, отобразить <A />, иначе ничего'.
  • Эти сокращения широко распространены, но вы не обязаны их использовать, если предпочитаете простой if.

On this page