Умовний рендеринг
Ваші компоненти часто матимуть потребу відображати різні речі в залежності від різних умов. У React ви можете умовно рендерити JSX, використовуючи синтаксис JavaScript: оператори if, && та ? :.
You will learn
- Як повертати різний 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)</h1> <ul> <Item isPacked={true} name="Космічний костюм" /> <Item isPacked={true} name="Шолом із золотим листям" /> <Item isPacked={false} name="Фото Тем О'Шонессі(Tam O'Shaughnessy)" /> </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>Список речей для пакування Саллі Райд(Sally Ride)</h1> <ul> <Item isPacked={true} name="Космічний костюм" /> <Item isPacked={true} name="Шолом із золотим листям" /> <Item isPacked={false} name="Фото Тем О'Шонессі(Tam O'Shaughnessy)" /> </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>Список речей для пакування Саллі Райд(Sally Ride)</h1> <ul> <Item isPacked={true} name="Космічний костюм" /> <Item isPacked={true} name="Шолом із золотим листям" /> <Item isPacked={false} name="Фото Тем О'Шонессі(Tam O'Shaughnessy)" /> </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>Список речей для пакування Саллі Райд(Sally Ride)</h1> <ul> <Item isPacked={true} name="Космічний костюм" /> <Item isPacked={true} name="Шолом із золотим листям" /> <Item isPacked={false} name="Фото Тем О'Шонессі(Tam O'Shaughnessy)" /> </ul> </section> ); }
Цей стиль добре працює для простих умов, але використовуйте його з розумом. Якщо ваші компоненти стають заплутаними через велику вкладену умовну розмітку, подумайте над “розпакуванням” дочірніх компонентів, щоб все виглядало охайніше. У React розмітка є частиною вашого коду, тому ви можете використовувати такі інструменти, як змінні та функції, щоб спростити складні вирази.
Логічний оператор AND (&&)
Ще одне поширене скорочення, з яким ви зіткнетеся — логічний оператор AND (&&) 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>Список речей для пакування Саллі Райд(Sally Ride)</h1> <ul> <Item isPacked={true} name="Космічний костюм" /> <Item isPacked={true} name="Шолом із золотим листям" /> <Item isPacked={false} name="Фото Тем О'Шонессі(Tam O'Shaughnessy)" /> </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>Список речей для пакування Саллі Райд(Sally Ride)</h1> <ul> <Item isPacked={true} name="Космічний костюм" /> <Item isPacked={true} name="Шолом із золотим листям" /> <Item isPacked={false} name="Фото Тем О'Шонессі(Tam O'Shaughnessy)" /> </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>Список речей для пакування Саллі Райд(Sally Ride)</h1> <ul> <Item isPacked={true} name="Космічний костюм" /> <Item isPacked={true} name="Шолом із золотим листям" /> <Item isPacked={false} name="Фото Тем О'Шонессі(Tam O'Shaughnessy)" /> </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>Список речей для пакування Саллі Райд(Sally Ride)</h1> <ul> <Item isPacked={true} name="Космічний костюм" /> <Item isPacked={true} name="Шолом із золотим листям" /> <Item isPacked={false} name="Фото Тем О'Шонессі(Tam O'Shaughnessy)" /> </ul> </section> ); }