- 700М доменів
- Cloud від Hostinger
- Quick Start
- Installation
- Describing the UI
- Adding Interactivity
- Managing State
- Escape Hatches
Спонсори
GET STARTED
LEARN 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>
);
}
Зверніть увагу, що деякі з компонентів 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>
);
}
Спробуйте відредагувати те, що повертається у обох випадках, і подивіться, як зміниться результат!
Зверніть увагу, як ви створюєте логіку розгалуження за допомогою операторів 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'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>
);
}
На практиці повернення 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, щоб зробити ваш код більш СУХИМ.
Умовний (тернарний) оператор (? :)
JavaScript має компактний синтаксис для запису умовного виразу - умовний оператор або "тернарний оператор".
Замість цього:
if (isPacked) {
return <li className="item">{name} ✔</li>;
}
return <li className="item">{name}</li>;
Можна записати так:
return (
<li className="item">
{isPacked ? name + ' ✔' : name}
</li>
);
Це можна прочитати як "якщо isPacked істинно, то (?) відрендерити 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>
);
}
Цей стиль добре працює у простих умовах, але використовуйте його помірковано. Якщо ваші компоненти захаращені занадто великою кількістю вкладеної умовної розмітки, подумайте про вилучення дочірніх компонентів, щоб навести лад. У React розмітка є частиною вашого коду, тому ви можете використовувати такі інструменти, як змінні та функції, щоб навести лад у складних виразах.
Логічний оператор AND (&&)
Ще один поширений ярлик, який ви можете зустріти, - це оператор логічного І (&&) JavaScript. Всередині React-компонентів він часто виникає, коли ви хочете відрендерити якийсь JSX, коли умова істинна, або не відрендерити нічого в іншому випадку. За допомогою && ви можете умовно відрендерити галочку, тільки якщо isPacked є істинною:
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>
);
}
А JavaScript вираз && повертає значення своєї правої частини (у нашому випадку, галочки), якщо ліва частина (наша умова) істинна. Але якщо умова має значення 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>
);
}
Як і раніше, це працює не лише для тексту, але й для довільного 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>
);
}
Якщо ви не знайомі з JavaScript, таке розмаїття стилів може спочатку здатися вам незрозумілим. Однак, вивчивши їх, ви зможете читати і писати будь-який JavaScript-код - і не тільки React-компоненти! Виберіть для початку той, якому ви віддаєте перевагу, а потім знову зверніться до цієї довідки, якщо забудете, як працюють інші.
- У React ви керуєте логікою розгалужень за допомогою JavaScript.
- Ви можете повернути вираз JSX умовно за допомогою інструкції
if. - Ви можете умовно зберегти деякий JSX у змінну, а потім включити його до іншого JSX за допомогою фігурних дужок.
- У JSX
{cond ? <A /> : <B />}означає "якщоcond, рендерити<A />, інакше<B />". - У JSX
{cond && <A />}означає "якщоcond, рендерити<A />, інакше нічого". - Ці комбінації є стандартними, але ви можете не використовувати їх, якщо віддаєте перевагу звичайним
if.
Показувати іконку для незавершених елементів з ? :
Використовуйте умовний оператор (cond ? a : b) для виведення ❌, якщо 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>
);
}
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>
);
}
Показати важливість елемента за допомогою &&
У цьому прикладі кожен Item отримує числову важливість пропу . Використовуйте оператор && для виділення "(Важливість: X)" курсивом, але лише для елементів, які мають ненульову важливість. Ваш список елементів має виглядати так:
- Скафандр (Важливість: 9)
- Шолом із золотим листям
- Фотографія Там(Важливість: 6)
Не забудьте додати пробіл між двома мітками!
function Item({ name, importance }) {
return (
<li className="item">
{name}
</li>
);
}
export default function PackingList() {
return (
<section>
<h1>Sally Ride's Packing List</h1>
<ul>
<Item
importance={9}
name="Space suit"
/>
<Item
importance={0}
name="Helmet with a golden leaf"
/>
<Item
importance={6}
name="Photo of Tam"
/>
</ul>
</section>
);
}
Це має спрацювати:
function Item({ name, importance }) {
return (
<li className="item">
{name}
{importance > 0 && ' '}
{importance > 0 &&
<i>(Importance: {importance})</i>
}
</li>
);
}
export default function PackingList() {
return (
<section>
<h1>Sally Ride's Packing List</h1>
<ul>
<Item
importance={9}
name="Space suit"
/>
<Item
importance={0}
name="Helmet with a golden leaf"
/>
<Item
importance={6}
name="Photo of Tam"
/>
</ul>
</section>
);
}
Зверніть увагу, що ви повинні написати importance > 0 && ..., а не importance && ..., щоб якщо значення дорівнює 0, 0 не виводилося як результат!
У цьому рішенні використовуються дві окремі умови для вставки пробілу між назвою та міткою важливості. Крім того, ви можете використати фрагмент з пробілом на початку: importance > 0 && <> <i>...</i></> або додати пробіл безпосередньо всередині <i>: importance > 0 && <i> ...</i>.
Рефакторинг серії ? : до if та змінних
Цей Drink компонент використовує низку ? : умов для відображення різної інформації залежно від того, чи проп name є "tea" або "coffee". Проблема полягає в тому, що інформація про кожен напій розподілена між декількома умовами. Рефакторингуйте цей код, щоб використовувати один оператор if замість трьох умов ? :.
function Drink({ name }) {
return (
<section>
<h1>{name}</h1>
<dl>
<dt>Part of plant</dt>
<dd>{name === 'tea' ? 'leaf' : 'bean'}</dd>
<dt>Caffeine content</dt>
<dd>{name === 'tea' ? '15–70 mg/cup' : '80–185 mg/cup'}</dd>
<dt>Age</dt>
<dd>{name === 'tea' ? '4,000+ years' : '1,000+ years'}</dd>
</dl>
</section>
);
}
export default function DrinkList() {
return (
<div>
<Drink name="tea" />
<Drink name="coffee" />
</div>
);
}
Після того, як ви переробили код для використання if, чи є у вас подальші ідеї, як його спростити?
Є кілька способів, але ось один з них:
function Drink({ name }) {
let part, caffeine, age;
if (name === 'tea') {
part = 'leaf';
caffeine = '15–70 mg/cup';
age = '4,000+ years';
} else if (name === 'coffee') {
part = 'bean';
caffeine = '80–185 mg/cup';
age = '1,000+ years';
}
return (
<section>
<h1>{name}</h1>
<dl>
<dt>Part of plant</dt>
<dd>{part}</dd>
<dt>Caffeine content</dt>
<dd>{caffeine}</dd>
<dt>Age</dt>
<dd>{age}</dd>
</dl>
</section>
);
}
export default function DrinkList() {
return (
<div>
<Drink name="tea" />
<Drink name="coffee" />
</div>
);
}
Тут інформація про кожен напій згрупована разом, а не розпорошена по декількох умовах. Це полегшує додавання нових напоїв у майбутньому.
Іншим рішенням може бути повне видалення умови шляхом переміщення інформації в об'єкти:
const drinks = {
tea: {
part: 'leaf',
caffeine: '15–70 mg/cup',
age: '4,000+ years'
},
coffee: {
part: 'bean',
caffeine: '80–185 mg/cup',
age: '1,000+ years'
}
};
function Drink({ name }) {
const info = drinks[name];
return (
<section>
<h1>{name}</h1>
<dl>
<dt>Part of plant</dt>
<dd>{info.part}</dd>
<dt>Caffeine content</dt>
<dd>{info.caffeine}</dd>
<dt>Age</dt>
<dd>{info.age}</dd>
</dl>
</section>
);
}
export default function DrinkList() {
return (
<div>
<Drink name="tea" />
<Drink name="coffee" />
</div>
);
}