Menu

Условный рендеринг в React: if, тернарный оператор и &&

Условный рендеринг в React это обычный JavaScript: инструкция if, тернарный оператор или && решают, какой JSX вернёт компонент. Каждый шаблон, лишний 0, который может вывести &&, возврат null и почему скрыть компонент не то же самое, что не рендерить его.

На этой странице есть исполняемые редакторы: меняйте, запускайте и сразу видите результат.

Условный рендеринг в 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 оставляет его смонтированным и сохраняет состояние. Выбирайте по тому, должно ли состояние сохраниться.

Иллюстрация языков программирования Coddy

Учитесь программировать с Coddy

НАЧАТЬ