Урок 3: Знакомство с JSX (основа синтаксиса React)

Сегодня мы разберем одну из самых фундаментальных тем, это JSX. Именно он придает React-компонентам тот самый узнаваемый вид и делает разработку интуитивно понятной.

Готовься познакомиться с синтаксисом, который сначала может показаться странным, но очень скоро станет твоим верным соратником.

Что такое JSX?

Давай начнем с самого главного, с определения. JSX это не HTML и не строка. Это синтаксическое расширение для JavaScript. Дословно эта аббревиатура расшифровывается как JavaScript + XML (XML это старый брат HTML, очень на него похожий по структуре).

Представь, что у тебя есть кубики LEGO двух разных видов, обычные кубики (это наш ванильный JavaScript) и кубики с особыми формами и креплениями (это JSX). JSX позволяет тебе использовать эти особые кубики прямо внутри коробки с обычными, чтобы строить более сложные и выразительные конструкции. React затем берет эти «особые кубики» и превращает их в обычные JavaScript-объекты, которые браузер может понять и отобразить.

Зачем это все нужно?

В далекие времена, до появления React и подобных библиотек, логика (JavaScript) и разметка (HTML) жили в совершенно разных файлах. Ты писал красивый HTML в одном файле, а потом в другом файле писал скрипты, которые искали элементы в этом HTML по идентификаторам или классам и как-то их меняли. Это было неудобно, потому что при изменении структуры HTML приходилось переписывать и логику и наоборот.

Создатели React предложили гениальную идею: а что если собрать всё, что относится к одному компоненту интерфейса (его внешний вид и логику), в одном месте? Так появился JSX. Теперь ты описываешь, как должен выглядеть твой интерфейс, прямо внутри JavaScript-кода, используя знакомый HTML-подобный синтаксис.

JSX, это не обязательное требование для работы с React. «Под капотом» JSX-разметка преобразуется в вызовы функции React.createElement(). Но поверь мне, после того как ты привыкнешь к JSX, ты никогда не захочешь возвращаться к ручному вызову этой функции. JSX делает код читаемым, предсказуемым и простым для понимания.

Основные правила написания JSX

JSX очень похож на HTML и это его главное преимущество. Однако, есть несколько важных отличий, которые нужно запомнить, чтобы избежать ошибок и разочарований на начальном этапе. Давай разберем их по порядку.

1. Все теги должны быть закрыты

В HTML некоторые теги могут жить без закрывающего партнера. Например, <br><img> или <input>. В JSX это недопустимо. Каждый тег, который ты открыл, должен быть явно закрыт.

Есть два способа закрыть тег:

  • Парный тег: Если у тебя есть содержимое между тегами, ты используешь открывающий и закрывающий тег.

    jsx
    // Правильно:
    <div>Привет, мир!</div>
    <span>Это текст в спэне.</span>
    
    // Ошибка (в JSX так нельзя):
    <div>Привет, мир!
  • Самозакрывающийся тег: Если у тега нет содержимого (как у <img> или <br>), ты должен закрыть его с помощью / перед закрывающей угловой скобкой.

    jsx
    // Правильно:
    <br />
    <img src="image.jpg" />
    <input type="text" />
    
    // Ошибка (в JSX так нельзя):
    <br>
    <img src="image.jpg">
    <input type="text">

Эта строгость связана с тем, что JSX преобразуется в JavaScript-объекты и транслятору (инструменту, который это делает) нужно четко понимать, где начинается и где заканчивается каждый элемент.

2. Используй className вместо class

Это, пожалуй, самое известное отличие. В HTML мы добавляем стили через атрибут class:

html
<div class="my-super-block">...</div>

В JavaScript же слово class является зарезервированным ключевым словом для создания классов. Чтобы избежать конфликта, в JSX был введен атрибут className.

jsx
// Правильно:
<div className="my-super-block">...</div>

// Ошибка (так не сработает и стили не применятся):
<div class="my-super-block">...</div>

Просто запомни, хочешь добавить CSS-класс, то пиши className. Со временем это дойдет до автоматизма.

3. Все имена атрибутов пишутся в camelCase

В HTML атрибуты могут быть в любом регистре, но обычно их пишут в нижнем регистре. В JSX, поскольку это часть JavaScript, большинство атрибутов пишутся в верблюжьей нотации (camelCase).

Это особенно важно для атрибутов, состоящих из нескольких слов.

Примеры:

  • onclick -> onClick

  • onchange -> onChange

  • tabindex -> tabIndex

  • maxlength -> maxLength

Есть одно исключение: атрибуты data-* и aria-* остаются в нижнем регистре, как в HTML, для совместимости.

jsx
<div data-id="123" aria-label="Описание элемента">...</div>

4. Один корневой элемент на компонент (или Фрагменты)

Это правило действовало долгое время: JSX-выражение должно возвращать один корневой элемент. Нельзя просто так взять и вернуть два соседних div-а.

Почему? Потому что JSX-код компилируется в вызовы React.createElement(). А эта функция первым аргументом принимает именно один элемент (тег или компонент).

jsx
// Ошибка! Два корневых элемента.
function MyComponent() {
  return (
    <div>Первый элемент</div>
    <div>Второй элемент</div>
  );
}

Как с этим бороться?

  • Обернуть в родительский div: Самый простой способ.

    jsx
    // Правильно:
    function MyComponent() {
      return (
        <div>
          <div>Первый элемент</div>
          <div>Второй элемент</div>
        </div>
      );
    }

    Недостаток: мы создаем лишний элемент в DOM, что иногда может мешать стилизации или семантике.

  • Использовать Фрагменты (<Fragment> или <>...</>): Это специальный компонент, который не создает лишнего узла в DOM.

    jsx
    // Вариант 1: Использовать полное имя
    import { Fragment } from 'react';
    
    function MyComponent() {
      return (
        <Fragment>
          <div>Первый элемент</div>
          <div>Второй элемент</div>
        </Fragment>
      );
    }
    
    // Вариант 2 (более популярный и удобный): Использовать короткий синтаксис
    function MyComponent() {
      return (
        <>
          <div>Первый элемент</div>
          <div>Второй элемент</div>
        </>
      );
    }

Встраивание выражений в JSX через фигурные скобки {}

А вот здесь начинается сама суть JSX. До этого момента наш JSX был просто статичной разметкой. Но сила React в том, что интерфейс динамичен и зависит от данных. Фигурные скобки {} это мост между статичной разметкой и динамическим JavaScript.

Внутри фигурных скобок ты можешь поместить любое валидное JavaScript-выражение.

Что такое выражение? Это любой фрагмент кода, который возвращает значение.

  • 2 + 2 (вернет 4)

  • user.firstName (вернет строку)

  • formatName(user) (вернет результат вызова функции)

  • isLoggedIn ? 'Выйти' : 'Войти' (вернет одну из строк)

1. Отображение переменных и значений

Самый частый случай использования, отобразить значение переменной.

jsx
function Greeting() {
  const userName = "Максим";
  const currentYear = new Date().getFullYear();

  return (
    <div>
      <h1>Привет, {userName}!</h1>
      <p>Сейчас {currentYear} год.</p>
      <p>Результат вычисления: {2 + 2 * 2}</p> {/* Отобразится "6" */}
    </div>
  );
}

Внутри {} ты можешь делать простые вычисления, обращаться к свойствам объектов и элементам массивов.

2. Использование JavaScript-объектов (например, для стилей)

Часто нужно задавать стили динамически. Для этого в React есть атрибут style. Но в отличие от HTML, где style принимает строку, в JSX он принимает JavaScript-объект.

Ключи этого объекта, это названия CSS-свойств, но опять же, записанные в camelCase.

jsx
function ColoredBox() {
  const boxStyle = {
    width: '100px',
    height: '100px',
    backgroundColor: 'lightcoral', // аналог background-color в CSS
    borderRadius: '8px', // аналог border-radius
    display: 'flex',
    justifyContent: 'center',
    alignItems: 'center'
  };

  return (
    <div style={boxStyle}>
      Я цветная коробка!
    </div>
  );
}

Ты также можешь задавать стили инлайн (прямо в разметке), но не забывай про двойные фигурные скобки. Первые для входа в JS-режим. Вторые, потому что передаем объект.

jsx
<div style={{ color: 'red', fontSize: '20px' }}>Красный текст</div>

3. Вызов функций внутри JSX

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

Форматирование:

jsx
function PriceDisplay() {
  const price = 99.99;

  const formatPrice = (amount) => {
    return `$${amount.toFixed(2)}`;
  };

  return (
    <p>Цена: {formatPrice(price)}</p> // Отобразится "Цена: $99.99"
  );
}

4. Рендеринг списков с помощью map()

Одна из самых мощных возможностей. Часто у нас есть массив данных (например, список товаров, комментариев, пользователей) и мы хотим отобразить их в виде списка HTML-элементов.

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

jsx
function TodoList() {
  const todos = [
    { id: 1, text: 'Изучить JSX', completed: true },
    { id: 2, text: 'Написать компонент', completed: false },
    { id: 3, text: 'Задеплоить приложение', completed: false }
  ];

  return (
    <ul>
      {todos.map((todoItem) => {
        return (
          <li key={todoItem.id}>
            {todoItem.text} {todoItem.completed ? '✅' : '⏳'}
          </li>
        );
      })}
    </ul>
  );
}

Обрати внимание на атрибут key! Когда ты рендеришь список, React просит тебя задать каждому элементу уникальный key. Это помогает React идентифицировать, какие элементы были изменены, добавлены или удалены, для эффективного обновления интерфейса. В качестве ключа обычно используют уникальный ID из данных. Если его нет, можно использовать индекс массива (аргумент index в map), но это считается плохой практикой, если порядок элементов может меняться.

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

Часто нужно показывать разный интерфейс в зависимости от условий (авторизован пользователь или нет, загружены данные или нет, день или ночь). JSX предоставляет несколько элегантных способов для этого.

  • С помощью оператора && (логическое И): Идеально, когда нужно показать/скрыть один элемент.

    jsx
    function Notification({ message, isVisible }) {
      return (
        <div>
          {isVisible && <div className="alert">{message}</div>}
        </div>
      );
    }

    Если isVisible true, то правая часть && (наш alert) будет отображена. Если false, то  React проигнорирует её.

  • С помощью тернарного оператора ? :: Идеально, когда есть два варианта.

    jsx
    function LoginButton({ isLoggedIn }) {
      return (
        <button>
          {isLoggedIn ? 'Выйти' : 'Войти'}
        </button>
      );
    }
  • С помощью отдельной переменной или функции: Самый читаемый способ для сложных условий.

    jsx
    function UserProfile({ user }) {
      let content;
    
      if (user) {
        content = <h1>Здравствуй, {user.name}!</h1>;
      } else {
        content = <h1>Пожалуйста, войдите в систему.</h1>;
      }
    
      return <div>{content}</div>;
    }

Практические задачи для закрепления

Давай попробуем применить знания на практике. Я рекомендую тебе не просто читать, а открыть твою среду разработки (например, Create React App проект из прошлого урока) и попробовать написать этот код.

Задача 1: Карточка пользователя

Создай компонент UserCard, который отображает информацию о пользователе.

  • Используй переменные для имени, фамилии, возраста и ссылки на аватар.

  • Добавь стили через объект style или className (если ты уже подключил CSS).

  • Сделай так, чтобы если возраст больше 18, отображалась надпись «Совершеннолетний», а если меньше «Несовершеннолетний».

Пример решения:

jsx
function UserCard() {
  const firstName = "Иван";
  const lastName = "Иванов";
  const age = 25;
  const avatarUrl = "https://example.com/avatar.jpg";

  const cardStyle = {
    border: '1px solid #ccc',
    borderRadius: '8px',
    padding: '16px',
    maxWidth: '300px'
  };

  return (
    <div style={cardStyle}>
      <img src={avatarUrl} alt="Аватар" width="50" />
      <h2>{firstName} {lastName}</h2>
      <p>Возраст: {age}</p>
      <p>{age >= 18 ? 'Совершеннолетний' : 'Несовершеннолетний'}</p>
    </div>
  );
}

Задача 2: Список дел

Создай компонент TodoList, который отображает список дел из массива.

  • Создай массив объектов todos, где каждый объект имеет свойства idtext и completed (булево значение).

  • Используй map() для рендера списка.

  • Не забудь про атрибут key.

  • Рядом с каждым делом поставьте галочку «✓», если оно выполнено и крестик «✕», если нет.

Пример решения:

jsx
function TodoList() {
  const todos = [
    { id: 1, text: 'Купить молоко', completed: true },
    { id: 2, text: 'Забрать посылку', completed: false },
    { id: 3, text: 'Позвонить маме', completed: false }
  ];

  return (
    <ul>
      {todos.map((todo) => (
        <li key={todo.id}>
          {todo.text} - {todo.completed ? '✓' : '✕'}
        </li>
      ))}
    </ul>
  );
}

Задача 3: Динамический блок с условным рендерингом

Создай компонент WelcomeBanner, который принимает проп isMorning (булево значение).

  • Если isMorning равен true, компонент должен показывать сообщение «Доброе утро!» и иконку солнца (☀️).

  • Если isMorning равен false, компонент должен показывать сообщение «Добрый вечер!» и иконку луны (🌙).

  • Используй для этого тернарный оператор прямо в JSX.

Пример решения:

jsx
function WelcomeBanner({ isMorning }) {
  return (
    <div>
      <h1>
        {isMorning ? 'Доброе утро! ☀️' : 'Добрый вечер! 🌙'}
      </h1>
    </div>
  );
}

// Чтобы проверить, можно передать разные пропсы:
// <WelcomeBanner isMorning={true} />
// <WelcomeBanner isMorning={false} />

Заключение

На этом уроке ты узнал, что такое JSX, какие у него есть правила (className, закрывающиеся теги, camelCase) и самое главное, научился встраивать JavaScript-логику в разметку с помощью фигурных скобок.

JSX это сердце React. Он дает тебе всю мощь JavaScript для описания пользовательского интерфейса. Двигаясь дальше, ты увидишь, что все компоненты строятся на этих принципах.

В следующих уроках мы углубимся в концепцию компонентов и пропсов (props), которая позволит тебе создавать по-настоящему переиспользуемые и гибкие кусочки твоего интерфейса. Это будет не менее увлекательно!

Если ты хочешь изучать все уроки курса последовательно, найти дополнительные материалы и задания, то добро пожаловать на полный курс с уроками по React для начинающих: https://max-gabov.ru/react-dlya-nachinaushih

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

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

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