Условный рендеринг
Вашим компонентам нужно часто отображать различные вещи в зависимости от различных условий. В 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>Список вещей Салли Райд</h1> <ul> <Item isPacked={true} name="Космический скафандр" /> <Item isPacked={true} name="Шлем с золотым листом" /> <Item isPacked={false} name="Фотография Тэма" /> </ul> </section> ); }
Обратите внимание, что у некоторых компонентов 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>Список вещей Салли Райд</h1> <ul> <Item isPacked={true} name="Космический скафандр" /> <Item isPacked={true} name="Шлем с золотым листом" /> <Item isPacked={false} name="Фотография Тэма" /> </ul> </section> ); }
Попробуйте отредактировать то, что возвращается в обоих случаях, и посмотрите, как изменится результат!
Обратите внимание, как вы создаёте разветвлённую логику с помощью операторов JavaScript if
и return
. В 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>Список вещей Салли Райд</h1> <ul> <Item isPacked={true} name="Космический скафандр" /> <Item isPacked={true} name="Шлем с золотым листом" /> <Item isPacked={false} name="Фотография Тэма" /> </ul> </section> ); }
На практике возврат 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
”.
Deep Dive
Если вы знакомы с объектно-ориентированным программированием, вы можете предположить, что два приведенных выше примера немного отличаются друг от друга, поскольку один из них может создавать два разных “экземпляра” <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>Список вещей Салли Райд</h1> <ul> <Item isPacked={true} name="Космический скафандр" /> <Item isPacked={true} name="Шлем с золотым листом" /> <Item isPacked={false} name="Фотография Тэма" /> </ul> </section> ); }
Этот стиль хорошо работает для простых условий, но используйте его в меру. Если ваши компоненты становятся запутанными из-за слишком большого количества вложенной условной разметки, подумайте об выделении дочерних компонентов, чтобы навести порядок. В React разметка является частью кода, поэтому вы можете использовать такие инструменты, как переменные и функции, чтобы привести в порядок сложные выражения.
Логический оператор И(&&
)
Еще одно часто встречающееся сокращение JavaScript логический оператор И (&&
). Внутри React-компонентов он часто используется, когда вам нужно отрендерить JSX, когда условие true, или не рендерить ничего. С помощью &&
вы можете условно рендерить галочку, если 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>Список вещей Салли Райд</h1> <ul> <Item isPacked={true} name="Космический скафандр" /> <Item isPacked={true} name="Шлем с золотым листом" /> <Item isPacked={false} name="Фотография Тэма" /> </ul> </section> ); }
JavaScript выражение && возвращает значение правой части (в нашем случае это галочка), если левая часть (наше условие) является true
. Но если наше условие — false
, тогда всё выражение становится false
. React рассматривает false
как “пустое место” в дереве JSX, прямо как null
или undefined
, и ничего не рендерит на этом месте.
Условное присвоение JSX к переменной
Когда сокращения мешают написанию понятного кода, то попробуйте использовать if
оператор и переменную. Вы можете переназначать переменные, объявленные с помощью let
, поэтому начните с предоставления содержимого по умолчанию, которое вы хотите отобразить, например, name:
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>Список вещей Салли Райд</h1> <ul> <Item isPacked={true} name="Космический скафандр" /> <Item isPacked={true} name="Шлем с золотым листом" /> <Item isPacked={false} name="Фотография Тэма" /> </ul> </section> ); }
Как и раньше, это работает не только для текста, но и для произвольного 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>Список вещей Салли Райд</h1> <ul> <Item isPacked={true} name="Космический скафандр" /> <Item isPacked={true} name="Шлем с золотым листом" /> <Item isPacked={false} name="Фотография Тэма" /> </ul> </section> ); }
Если вы не знакомы с JavaScript, то такое разнообразие стилей может показаться поначалу ошеломляющим. Однако их изучение поможет вам читать и писать любой JavaScript код, а не только React-компоненты! Выберите тот, который вам больше нравится, и при необходимости обратитесь к этому справочнику, если вы забудете, как работают другие.
Recap
- В React вы управляете логикой ветвления с помощью JavaScript.
- Вы можете условно возвращать JSX-выражение с помощью оператора
if
. - Вы можете условно сохранить JSX в переменную и затем включить её в другой JSX с помощью фигурных скобок.
- В JSX выражение
{cond ? <A /> : <B />}
означает “еслиcond
, то отрендерить<A />
, иначе<B />
”. - В JSX выражение
{cond && <A />}
означает “еслиcond
, то отрендерить<A />
, иначе ничего”. - Эти сокращения являются общепринятыми, но эти сокращения необязательно использовать, если вы предпочитаете простой
if
.
Challenge 1 of 3: Показать иконку для неупакованных вещей с ? :
Используйте тернарный оператор (cond ? a : b
), чтобы отрендерить❌, если isPacked
не равен true
.
function Item({ name, isPacked }) { return ( <li className="item"> {name} {isPacked && '✅'} </li> ); } export default function PackingList() { return ( <section> <h1>Список вещей Салли Райд</h1> <ul> <Item isPacked={true} name="Космический скафандр" /> <Item isPacked={true} name="Шлем с золотым листом" /> <Item isPacked={false} name="Фотография Тэма" /> </ul> </section> ); }