Условный рендеринг в React означает выбор того, что возвращает компонент, обычным JavaScript: инструкцией if до return, тернарным оператором cond ? a : b внутри JSX или cond && <Thing />, чтобы показать что-то или ничего. Никакого особого синтаксиса шаблонов учить не нужно.
Нажмите кнопку, и переключатся и сообщение, и подпись, потому что каждый тернарный оператор выбирает другую строку при следующем рендере. Замените useState(false) на useState(true), и превью начнёт в состоянии входа.
Инструкции if и ранний return
Фигурные скобки JSX принимают выражения, а не инструкции, поэтому написать {if (x) ...} внутри разметки нельзя. Зато до return можно написать любой if. Когда целое состояние компонента выглядит иначе (загрузка, ошибка, пусто), возвращайтесь раньше для каждого случая, а основную разметку оставьте для обычного.
Каждая кнопка переводит почтовый ящик в другое состояние, и у каждого состояния своя короткая и понятная ветка. Ранние return держат основной путь внизу без вложенности.
Тернарный оператор внутри JSX
Когда меняется только небольшая часть разметки, тернарный оператор прямо в строке держит её вместе: {isOpen ? <CloseIcon /> : <MenuIcon />}. Тернарные операторы хорошо работают для двух вариантов. Вложенные тернарные операторы для трёх и больше быстро становятся трудночитаемыми:
// Hard to follow
{status === 'loading' ? <Spinner /> : status === 'error' ? <ErrorBox /> : <List />}
Увидев такое, перенесите логику в цепочку if до return (как выше) или в объект-карту (ниже).
&& и лишний 0
cond && <Thing /> рендерит <Thing />, когда cond истинно, и ничего, когда оно равно false. Это работает, потому что && возвращает левую часть, когда она ложна, а React ничего не рендерит для false, null и undefined.
Ловушка в том, что 0 тоже ложное значение, а числа React рендерит. Поэтому count && <Badge /> при счётчике 0 выводит на страницу буквальный 0.
Без непрочитанных сообщений первая строка показывает «Broken: 0», а вторая ничего не показывает после «Fixed:». Нажмите New message, и обе совпадут; нажмите Mark all read, и 0 вернётся. Решение: дать && настоящее булево значение: unread > 0, items.length > 0 или Boolean(unread). У пустой строки '' в принципе та же проблема, но она рендерится как ничего видимого, поэтому её редко замечают.
Возврат null
Компонент может вернуть null, чтобы ничего не рендерить. Хорошо подходит баннер с предупреждением, который появляется, только когда есть о чём предупредить: родитель всегда рендерит <Warning />, а решает сам компонент.
Следите за консолью: функция Warning выводит сообщение при каждом рендере, включая те, где она возвращает null. Возврат null пропускает вывод, а не работу. Её хуки и эффекты всё равно выполняются, поэтому если компонент дорогой или что-то запускает (таймер, подписку), решайте в родителе и вообще его не рендерите.
JSX в переменной
JSX это значение, поэтому его можно присвоить переменной, собрать с помощью инструкций if и потом вставить в разметку. Это помогает, когда одна часть большого макета зависит от нескольких условий.
function Checkout({ cart, user }) {
let action;
if (!user) {
action = <a href="/login">Log in to check out</a>;
} else if (cart.length === 0) {
action = <p>Your cart is empty.</p>;
} else {
action = <button>Pay now</button>;
}
return (
<section>
<h2>Your cart</h2>
{action}
</section>
);
}
Выбор одного из нескольких компонентов через объект
Когда выбор звучит как «один из многих», объект, который сопоставляет каждому значению компонент, короче длинной цепочки if или switch, а добавление варианта занимает одну строку.
TABS[tab] выбирает компонент, а <Panel /> его рендерит. Переменная должна начинаться с заглавной буквы: JSX считает <panel /> тегом HTML. Добавьте в TABS запись notifications со своим компонентом, и появится четвёртая кнопка.
Скрыть не то же самое, что не рендерить
Сделать что-то невидимым можно двумя способами, и ведут они себя по-разному. show && <Counter /> удаляет компонент из дерева, когда show ложно. React размонтирует его и выбрасывает состояние, поэтому при возвращении он начинает с нуля. Скрытие через CSS (style={{ display: show ? 'block' : 'none' }}) оставляет его смонтированным, и состояние сохраняется.
Понажимайте оба счётчика, снимите флажок, затем поставьте снова. Первый счётчик вернулся к 0, а второй всё ещё хранит своё число. Ни один вариант не ошибочен: удаление подходит для формы, которая каждый раз должна начинаться пустой, а скрытие для вкладок, у которых нужно сохранить позицию прокрутки или ввод. Страница о рендеринге объясняет, как React решает, что компонент между рендерами тот же самый.
React 19.2 добавляет третий вариант, <Activity mode="hidden">, который скрывает детей и сохраняет их состояние, как CSS, а также очищает их эффекты, пока они снова не будут показаны.
Условные пропсы и атрибуты
Условия касаются не только того, какие элементы появляются. Любой пропс может принимать вычисленное значение, поэтому часто достаточно тернарного оператора или сравнения внутри атрибута:
<button disabled={!canSave} className={hasError ? 'field error' : 'field'}>
Save
</button>
<input aria-invalid={hasError} placeholder={user ? user.email : 'you@example.com'} />
Когда значение пропса равно undefined, React полностью опускает атрибут, и это аккуратный способ добавлять атрибут лишь иногда: title={isTruncated ? fullText : undefined}. Для булевых атрибутов вроде disabled и checked передавайте true или false, и React добавит или уберёт их.
Условия в списках
Чтобы исключить элементы из списка, отфильтруйте массив перед map, а не возвращайте null изнутри map. items.filter((i) => i.done).map(...) читается так, как работает, а страница о списках и ключах показывает это на запускаемом примере.
Часто задаваемые вопросы
Как написать if внутри JSX?
Поместить инструкцию if в фигурные скобки JSX нельзя, потому что скобки принимают выражения. Используйте тернарный оператор (cond ? a : b) или && внутри JSX либо выполните if до return и сохраните JSX в переменной.
Почему мой компонент показывает 0?
count && <Badge /> возвращает сам count, когда он равен 0, а React рендерит число 0. Сделайте левую часть настоящим булевым значением: count > 0 && <Badge />.
Как ничего не рендерить в React?
Верните из компонента null или поместите в JSX null, undefined, false или true. React не рендерит ничего из этого.
Выполняется ли компонент, который возвращает null?
Да. Его функция выполняется, его хуки выполняются, и его эффекты срабатывают. Возврат null означает только, что он ничего не добавляет на страницу. Чтобы полностью пропустить работу, не рендерите компонент в родителе.
Скрывать компонент через CSS или удалять?
Удаление (show && <Panel />) размонтирует компонент, поэтому его состояние выбрасывается и в следующий раз начинается заново. Скрытие через display: none оставляет его смонтированным и сохраняет состояние. Выбирайте по тому, должно ли состояние сохраниться.