Перейти к содержимому

3. JSX синтаксис

Иллюстрация к уроку

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

Представьте, что вы пишете HTML внутри JavaScript. Это и есть JSX!

Зачем использовать JSX?

  1. Декларативность: Описание UI становится более интуитивным и легким для понимания.
  2. Знакомый синтаксис: Разработчикам, знакомым с HTML, очень легко адаптироваться.
  3. Повышенная безопасность: JSX предотвращает инъекции (XSS) по умолчанию, поскольку он преобразует все значения, вложенные в JSX, в строки перед рендерингом.
  4. Производительность: Babel компилирует JSX в оптимизированные вызовы React.createElement(), что React может использовать для построения эффективного виртуального DOM.

Важно понимать, что браузеры не понимают JSX напрямую. Ваш код на JSX транспилируется (обычно с помощью Babel) в обычный JavaScript-код (вызовы React.createElement()) перед тем, как браузер его выполнит.

JSX очень похож на HTML, но есть несколько ключевых отличий.

// Простой JSX элемент
const greeting = <h1>Привет, React!</h1>;
// JSX элемент с атрибутами (обратите внимание на className вместо class)
const button = <button className="my-button" onClick={() => alert('Нажата!')}>
Нажми меня
</button>;
// Самозакрывающийся тег
const image = <img src="logo.png" alt="React Logo" />;
// Несколько элементов должны быть обернуты в один родительский элемент (или фрагмент)
const appContent = (
<div>
{greeting}
{button}
{image}
</div>
);

Вы можете вставлять любые JavaScript-выражения в JSX, используя фигурные скобки {}.

const userName = 'Студент';
const userId = 123;
const isActive = true;
const userInfo = (
<div>
<h2>Пользователь: {userName}</h2> {/* Переменная */}
<p>ID: {userId * 2}</p> {/* Арифметическое выражение */}
<p>Статус: {isActive ? 'Активен' : 'Неактивен'}</p> {/* Тернарный оператор */}
<p>Дата: {new Date().toLocaleDateString()}</p> {/* Вызов функции */}
</div>
);

Комментарии внутри JSX пишутся как JavaScript-комментарии, но обернутые в фигурные скобки.

const productCard = (
<div>
{/* Это комментарий внутри JSX */}
<h3>Название продукта</h3>
{/* <p>Этот параграф не будет отображен, так как он закомментирован как элемент</p> */}
<p>Цена: 19.99</p>
</div>
);

Современный React использует функциональные компоненты и хуки. JSX является неотъемлемой частью их работы.

import React, { useState } from 'react';
type CounterProps = {
initialValue?: number;
};
function Counter({ initialValue = 0 }: CounterProps) {
const [count, setCount] = useState(initialValue);
return (
<div style={{ padding: '20px', border: '1px solid gray' }}>
<h2>Счетчик: {count}</h2>
<button onClick={() => setCount(count + 1)}>
Увеличить
</button>
<button onClick={() => setCount(count - 1)} style={{ marginLeft: '10px' }}>
Уменьшить
</button>
{/* Условный рендеринг на основе значения count */}
{count % 2 === 0 && <p>Число четное!</p>}
{count === 5 && <p>Достигнуто 5!</p>}
</div>
);
}
// Пример использования:
// <Counter initialValue={10} />

JSX-элемент должен иметь только один корневой элемент. Если вам нужно вернуть несколько элементов без лишней обертки, используйте Фрагменты.

// Ошибка: Возвращает несколько корневых элементов
// function MyComponent() {
// return (
// <p>Первый параграф</p>
// <p>Второй параграф</p>
// );
// }
// Правильно: Использование сокращенного синтаксиса фрагмента
function MyComponent() {
return (
<>
<p>Первый параграф</p>
<p>Второй параграф</p>
</>
);
}
// Альтернатива с явным React.Fragment (полезно, если нужен атрибут key)
function AnotherComponent() {
return (
<React.Fragment>
<span>Элемент 1</span>
<span>Элемент 2</span>
</React.Fragment>
);
}

При рендеринге списков элементов с помощью метода map, каждый элемент должен иметь уникальный key пропс. Это помогает React эффективно обновлять списки.

const items = ['Яблоко', 'Банан', 'Вишня'];
function ShoppingList() {
return (
<ul>
{items.map((item, index) => (
// Key должен быть уникальным среди соседних элементов.
// Лучше использовать ID из данных, если они есть. index - как крайняя мера.
<li key={index}>{item}</li>
))}
</ul>
);
}
  1. Несколько корневых элементов без обертки:
    // НЕПРАВИЛЬНО
    // return <p>Привет</p><p>Мир</p>;
    // ПРАВИЛЬНО
    return <> <p>Привет</p><p>Мир</p> </> ;
  2. Использование class вместо className: HTML-атрибут class в JSX конфликтует с зарезервированным словом JavaScript, поэтому используется className.
  3. Использование for вместо htmlFor: Аналогично, for в JSX заменяется на htmlFor для связи label с input.
  4. Забывание key при рендеринге списков: Может привести к проблемам с производительностью и некорректному поведению UI.
  5. Попытка использовать HTML-комментарии <!-- --> внутри JSX: Используйте {/* */} для комментариев внутри JSX.
  6. Вставлять объекты в JSX напрямую (кроме исключений, как стили):
    const myObject = { name: 'Alice' };
    // НЕПРАВИЛЬНО: <div>{myObject}</div> -- React не знает, как рендерить объект.
    // ПРАВИЛЬНО: <div>{myObject.name}</div>

Создайте функциональный компонент UserCard, который принимает пропсы name, age и email. Компонент должен отображать эту информацию внутри div, используя JSX. Добавьте условный рендеринг, чтобы отображать текст “Совершеннолетний”, если возраст пользователя 18 или больше.

Попробуйте изменить код прямо здесь и увидите результат справа! 👇