Урок 11: Условный рендеринг в React

Сегодня нас ждет одна из самых важных и часто используемых тем, это условный рендеринг.

Представьте себе обычный веб-сайт. Вы заходите в интернет-магазин и сайт приветствует вас по имени. Вы администратор и у вас появляются кнопки для управления контентом. Вы не залогинены и вам показывают форму входа. Вся эта логика «показывать одно, но не показывать другое» и есть условный рендеринг. В обычном JavaScript мы бы использовали if...else или switch. В React мы используем мощь JSX и несколько изящных подходов, о которых мы и поговорим.

Что такое условный рендеринг?

Если говорить просто, условный рендеринг в React это способ рендерить разные JSX-элементы или компоненты в зависимости от условий. Эти условия почти всегда определяются состоянием (state) или пропсами (props) вашего компонента. React обновляет интерфейс реактивно, как только состояние меняется, поэтому при изменении условия контент на странице меняется мгновенно, без её перезагрузки.

В этом уроке мы детально разберем три основных инструмента для условного рендеринга:

  1. Логический оператор && для простого показа/скрытия.

  2. Тернарный оператор ? : для выбора между двумя вариантами.

  3. Использование переменных для сложной логики.

Давайте начнем с самого простого и понятного способа.

Показываем и скрываем элементы с помощью &&

Этот оператор, настоящая рабочая лошадка в арсенале React-разработчика. Он идеально подходит для ситуаций, когда вам нужно показать что-то одно, если условие истинно и ничего не показывать, если условие ложно.

Как это работает?

В JavaScript оператор && (логическое И) работает по следующему принципу: он возвращает первый ложный операнд или последний истинный. Например, true && 'Привет' вернет 'Привет'. А false && 'Привет' вернет false.

Почему это так полезно в JSX? Потому что JSX умеет отображать разные типы данных. Строки, числа, JSX-элементы, все это будет отрисовано. А вот значения falsenull и undefined JSX просто игнорирует, оставляя пустое место. Именно это свойство и позволяет нам легко скрывать элементы.

Рассмотрим на практическом примере. Допустим, у нас есть компонент уведомления, которое должно появляться только тогда, когда есть новое сообщение.

jsx
import React, { useState } from 'react';

function Notification() {
  // Состояние, которое хранит текст нашего уведомления
  const [message, setMessage] = useState('');

  return (
    <div>
      {/* Кнопка, чтобы показать уведомление */}
      <button onClick={() => setMessage('Вы получили новое сообщение!')}>
        Показать уведомление
      </button>

      {/* Кнопка, чтобы скрыть уведомление (очистить сообщение) */}
      <button onClick={() => setMessage('')}>
        Скрыть уведомление
      </button>

      {/* Условный рендеринг с помощью && */}
      {/* Если message не пустая строка (то есть true), то рендерим div */}
      {message && (
        <div style={{ padding: '10px', backgroundColor: 'lightblue', marginTop: '10px' }}>
          {message}
        </div>
      )}
    </div>
  );
}

export default Notification;

Что происходит в этом коде?

  1. Мы создаем состояние message с помощью useState. Изначально оно пустое ('').

  2. У нас есть две кнопки. Одна устанавливает message в текст уведомления, другая очищает его.

  3. Самая важная строка: {message && (...)}. Давайте разберем её:

    • Если message пустая строка (''), это false в логическом контексте. Выражение false && (div) сразу возвращает false. JSX видит false и ничего не рендерит.

    • Когда пользователь нажимает «Показать уведомление», message становится строкой. Непустая строка это true. Выражение true && (div) возвращает наш div с уведомлением и JSX его отрисовывает.

Важный нюанс! Будьте осторожны с числами 0. В JavaScript 0 является false. Если бы наше условие было {count && <div>...</div>} и count равнялся 0, то React отрендерил бы 0 на страницу, а не ничего. Чтобы этого избежать, всегда убеждайтесь, что слева от && находится строго булево значение. Например: {count > 0 && <div>Есть новые items!</div>}.

Практическая задача 1:
Создайте компонент WarningBanner. Он должен показывать красный баннер с текстом «Внимание! Сайт в режиме разработки», если проп warn равен true. Если warn равен false, баннер не должен отображаться. Используйте оператор &&.

Тернарный оператор ? : для выбора между двумя вариантами

Что делать, если нам нужно не просто показать или скрыть элемент, а выбрать между двумя разными элементами или компонентами? Здесь на помощь приходит тернарный оператор. Это концентрированная и очень читаемая форма записи if...else.

Синтаксис тернарного оператора:
условие ? выражение_если_истина : выражение_если_ложь

Если условие истинно, выполняется и возвращается первое выражение. Если ложно, то второе.

Классический пример: переключатель логина.

Пользователь может быть либо авторизован (isLoggedIn = true), либо нет (isLoggedIn = false). В зависимости от этого мы покажем либо приветствие, либо кнопку для входа.

jsx
import React, { useState } from 'react';

function LoginControl() {
  const [isLoggedIn, setIsLoggedIn] = useState(false);

  const handleLogin = () => setIsLoggedIn(true);
  const handleLogout = () => setIsLoggedIn(false);

  return (
    <div>
      {/* Тернарный оператор в действии */}
      {isLoggedIn ? (
        // Если isLoggedIn true, показываем приветствие и кнопку Выйти
        <div>
          <h2>Добро пожаловать назад!</h2>
          <button onClick={handleLogout}>Выйти</button>
        </div>
      ) : (
        // Если isLoggedIn false, показываем кнопку Войти
        <div>
          <h2>Пожалуйста, войдите в систему.</h2>
          <button onClick={handleLogin}>Войти</button>
        </div>
      )}
    </div>
  );
}

export default LoginControl;

Этот код очень легко читается: «Если пользователь вошел в систему, то покажи приветствие, иначе покажи предложение войти».

Тернарный оператор можно использовать не только для больших блоков JSX, но и для мелких деталей внутри атрибутов. Например, для динамического изменения CSS-класса.

jsx
function Notification({ message, type }) {
  return (
    <div className={type === 'error' ? 'alert alert-error' : 'alert alert-info'}>
      {message}
    </div>
  );
}

В этом примере класс элемента div будет зависеть от пропса type. Если type равен 'error', установится класс alert alert-error, в противном случае alert alert-info.

Практическая задача 2:
Создайте компонент ThemeToggle. Он должен иметь состояние isDarkMode (булево значение) и кнопку для его переключения. Фон всей страницы и цвет текста должны меняться в зависимости от темы (например, светлый фон и черный текст для светлой темы, темный фон и белый текст для темной). Используйте тернарный оператор для условного задания CSS-стилей инлайново или CSS-классов.

Использование переменных для условного рендеринга

Иногда логика определения того, что нужно рендерить, становится слишком сложной для того, чтобы умещать её прямо в JSX с помощью && или ? :. В таких случаях лучше всего вынести её в отдельные переменные. Этот подход делает код чище, понятнее и его легче поддерживать.

Сложный пример: загрузка данных.

Рассмотрим компонент, который загружает данные с сервера. У него может быть три состояния: загрузка, успешный результат и ошибка.

jsx
import React, { useState, useEffect } from 'react';

function DataFetcher() {
  const [data, setData] = useState(null);
  const [isLoading, setIsLoading] = useState(true);
  const [error, setError] = useState(null);

  // Имитируем загрузку данных
  useEffect(() => {
    setTimeout(() => {
      // Эмуляция успешного ответа
      // setData({ name: 'Максим', profession: 'Разработчик' });
      // setIsLoading(false);

      // Эмуляция ошибки
      setError('Не удалось загрузить данные!');
      setIsLoading(false);
    }, 2000);
  }, []);

  // 1. Объявляем переменную, в которую положим наш JSX
  let content;

  // 2. Логика определения, что же положить в content
  if (isLoading) {
    content = <div>Загрузка...</div>;
  } else if (error) {
    content = <div style={{ color: 'red' }}>Ошибка: {error}</div>;
  } else {
    content = (
      <div>
        <h3>Данные пользователя:</h3>
        <p>Имя: {data.name}</p>
        <p>Профессия: {data.profession}</p>
      </div>
    );
  }

  // 3. В JSX мы просто используем нашу переменную
  return (
    <div>
      <h2>Получение данных</h2>
      {content}
    </div>
  );
}

export default DataFetcher;

Почему этот подход хорош?

  • Читаемость. Логика рендеринга отделена от разметки. Легко понять, какой контент будет показан в каждом из состояний.

  • Гибкость. Вы можете использовать всю мощь JavaScript (if/elseswitch/case, функции) для описания сложных условий.

  • Переиспользуемость. Часть этой логики можно легко вынести в отдельную функцию.

Этот метод часто используется в крупных, сложных компонентах, где условия рендеринга зависят от множества факторов.

Практическая задача 3:
Модифицируйте компонент из Задачи 2 (ThemeToggle). Вместо тернарного оператора внутри JSX, используйте переменную. Объявите переменную themeClass (или themeStyle) и с помощью if/else присвойте ей строку с именем CSS-класса (или объект со стилями). Затем используйте эту переменную в JSX.

Комбинирование подходов и важные замечания

В реальных проектах вы будете часто комбинировать все три подхода. Например, вы можете использовать переменную для хранения основного контента, а внутри него тернарный оператор для мелких деталей.

jsx
function UserProfile({ user }) {
  let profileContent;

  if (!user) {
    profileContent = <p>Пользователь не найден.</p>;
  } else {
    profileContent = (
      <div>
        <h2>{user.name}</h2>
        <p>Email: {user.email}</p>
        {/* Используем && внутри блока else */}
        {user.isAdmin && <span>(Администратор)</span>}
        {/* Используем тернарный оператор для статуса */}
        <p>Статус: {user.isOnline ? ' В сети' : '⚫ Не в сети'}</p>
      </div>
    );
  }

  return <div className="profile">{profileContent}</div>;
}

Запрет на рендеринг с помощью null

Иногда вам может понадобиться полностью скрыть компонент, чтобы он не рендерился вообще. В этом случае вы можете вернуть null из вашего функционального компонента.

jsx
function WarningBanner({ warn }) {
  // Если warn false, компонент ничего не рендерит
  if (!warn) {
    return null;
  }

  return <div className="warning">Предупреждение!</div>;
}

Возврат null не «уничтожает» компонент, его методы состояния (useStateuseEffect) будут работать как обычно. Это просто команда React не создавать никакого DOM для этого компонента в данный момент.

Эльвира в чате: «Максим, а есть ли разница в производительности между этими способами?»

Отличный вопрос, Эльвира! В подавляющем большинстве случаев разницы нет. Современные JavaScript-движки очень хорошо оптимизируют такие операции. Выбор между &&? : и переменными это прежде всего вопрос читаемости и личных предпочтений. Пишите код так, чтобы его было легко понять вам и вашей команде через полгода.

Итоги урока

Сегодня мы с вами освоили один из краеугольных камней React, условный рендеринг. Давайте кратко повторим:

  1. && (логическое И). Ваш лучший друг для простого показа/скрытия элемента. «Покажи это, только если условие истинно».

  2. ? : (тернарный оператор). Идеален для выбора между двумя вариантами. «Если условие истинно, покажи это, иначе покажи вот это».

  3. Переменные. Мощный инструмент для сложной логики рендеринга. Позволяет вынести условие из JSX, делая код чище и понятнее.

Условный рендеринг это то, что делает ваши интерфейсы «живыми» и интерактивными. Он напрямую связывает состояние приложения с тем, что видит пользователь.

Хотите освоить React на практике?

Посмотрите полный курс с уроками по React для начинающих, где мы шаг за шагом, от самых основ до продвинутых тем, построим настоящее React-приложение.

Поделиться статьей:
Поддержать автора блога

Поддержка автора осуществляется с помощью специальной формы ниже, предоставленной сервисом «ЮMoney». Все платёжные операции выполняются на защищённой странице сервиса, что обеспечивает их корректность и полную безопасность.

Персональные рекомендации
Оставить комментарий