Условный рендеринг

Условный рендеринг — механизм отображения разных UI-элементов в зависимости от состояния или пропсов компонента; в React реализуется через стандартные JavaScript-конструкции внутри JSX.

Зачем нужно

Практически любой реальный UI содержит условный рендеринг: «покажи спиннер если загружается», «покажи сообщение об ошибке если запрос упал», «покажи меню если пользователь авторизован». Знание идиоматических паттернов помогает писать читаемый JSX и избегать распространённых ловушек (рендеринг числа 0).

Где используется

  • Loading states: isLoading && <Spinner />
  • Error states: error ? <ErrorMessage /> : <Content />
  • Авторизация: user ? <Dashboard /> : <Login />
  • Условные секции, кнопки, бейджи

Паттерны условного рендеринга

function UserProfile({ user, isLoading, error }) {

  // 1. Ранний возврат (early return) — для крупных ветвей
  if (isLoading) return <Spinner />;
  if (error) return <ErrorMessage message={error.message} />;
  if (!user) return <EmptyState />;

  // Основной рендер только когда данные есть
  return (
    <div className="profile">
      <h1>{user.name}</h1>

      {/* 2. Тернарный оператор — два взаимоисключающих варианта */}
      {user.isPremium
        ? <PremiumBadge />
        : <UpgradeButton />
      }

      {/* 3. Логическое И (&&) — показать или ничего */}
      {user.isAdmin && <AdminPanel />}

      {/* 4. Нуллиш оператор ?? — fallback для null/undefined */}
      <p>{user.bio ?? 'Биография не указана'}</p>

      {/* 5. Переменная с JSX — для сложных условий */}
      {renderActions(user)}
    </div>
  );
}

// 5. Вынесение условной логики в переменную
function renderActions(user) {
  if (user.isBlocked) {
    return <span className="blocked">Заблокирован</span>;
  }
  if (user.isPending) {
    return <span className="pending">На проверке</span>;
  }
  return (
    <div className="actions">
      <button>Написать</button>
      <button>Подписаться</button>
    </div>
  );
}

switch/object map — для множества вариантов

// Много вариантов → switch или объект вместо цепочки if/else
const STATUS_COMPONENTS = {
  loading: <Spinner />,
  error: <ErrorIcon />,
  success: <CheckIcon />,
  idle: null,
};

function StatusIndicator({ status }) {
  // Объект-маппинг чище цепочки тернарников
  return STATUS_COMPONENTS[status] || null;
}

// Или компонент-переключатель
function OrderStatus({ status }) {
  switch (status) {
    case 'pending':   return <Badge color="yellow">Ожидает</Badge>;
    case 'shipped':   return <Badge color="blue">Отправлен</Badge>;
    case 'delivered': return <Badge color="green">Доставлен</Badge>;
    case 'cancelled': return <Badge color="red">Отменён</Badge>;
    default:          return null;
  }
}

Условный рендеринг и CSS

// Для частых переключений: скрывать через CSS, не размонтировать
// (сохраняет state, избегает анимаций)
function Drawer({ isOpen, children }) {
  return (
    <div
      className={`drawer ${isOpen ? 'drawer--open' : 'drawer--closed'}`}
      // aria-hidden важен для доступности
      aria-hidden={!isOpen}
    >
      {children}
    </div>
  );
}

// Для редких переключений: размонтирование экономит память
function Modal({ isOpen, children }) {
  if (!isOpen) return null; // компонент размонтируется, state сбрасывается
  return <div className="modal">{children}</div>;
}

Частые ошибки

  • {count && <Component />} рендерит 0 — если count === 0, в JSX вставляется число 0; используйте {count > 0 && <Component />} или {!!count && <Component />}.
  • Тернарник для сложных условий — 4+ вложенных тернарника нечитаемы; выносите логику в переменную или компонент.
  • Нет обработки null/undefined{user.name} без проверки выбрасывает ошибку если user не загружен; используйте optional chaining {user?.name}.

Связанные темы

Ресурсы