Урок 26 из 49 · Месяц 4. React

Знакомство с React, установка и JSX

Содержание урока

В этом уроке мы познакомимся с React — самой популярной библиотекой для создания интерфейсов. Разберёмся, зачем она нужна, создадим первый проект через Vite, поймём, что такое JSX, и выведем на страницу свои первые компоненты. Всё, что вы выучили про JavaScript за прошлые месяцы, здесь пригодится каждый день.

Что такое React

React — это JavaScript-библиотека для создания пользовательских интерфейсов (UI): кнопок, списков, форм, целых страниц. Её создали в Facebook (сейчас Meta), и сегодня на React написаны тысячи сайтов и приложений.

Главная идея React — интерфейс собирается из компонентов. Компонент — это кусочек интерфейса со своей разметкой и логикой: шапка сайта, карточка товара, кнопка «Купить».

Аналогия: конструктор LEGO. Вы один раз делаете деталь «карточка товара», а потом используете её сколько угодно раз — на главной странице, в каталоге, в корзине. Если поменять деталь, она поменяется везде.

<App>
 ├── <Header>
 │    └── <Menu>
 ├── <ProductList>
 │    ├── <ProductCard>
 │    ├── <ProductCard>
 │    └── <ProductCard>
 └── <Footer>

Зачем React, если есть обычный JavaScript

В уроке Введение в DOM мы меняли страницу вручную: находили элемент, создавали новый, добавляли класс. Для маленькой страницы это нормально. Но представьте интернет-магазин: корзина, фильтры, счётчик товаров в шапке, уведомления. Изменилось одно число — и нужно не забыть обновить его в пяти местах.

Сравним. Обычный JavaScript — императивный подход: вы командуете браузеру каждый шаг.

const button = document.querySelector('#btn');
const counter = document.querySelector('#counter');
let count = 0;

button.addEventListener('click', () => {
  count++;
  counter.textContent = count; // сами вручную обновляем DOM
});

React — декларативный подход: вы описываете, как должен выглядеть интерфейс при текущих данных, а React сам решает, что изменить в DOM.

import { useState } from 'react';

function Counter() {
  const [count, setCount] = useState(0);

  return <button onClick={() => setCount(count + 1)}>Нажато: {count}</button>;
}

Пока не пугайтесь useState — это тема отдельного урока. Важно увидеть идею: мы не трогаем DOM руками. Мы меняем данные, а React обновляет страницу.

Как React обновляет страницу

Работа с настоящим DOM — относительно медленная операция. Поэтому React держит в памяти лёгкую копию интерфейса (её часто называют виртуальным DOM). Когда данные меняются, React:

  1. строит новую версию интерфейса в памяти;
  2. сравнивает её со старой;
  3. меняет в настоящем DOM только то, что действительно изменилось.

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

Установка React через Vite

Раньше проекты создавали через Create React App, но он устарел и больше не рекомендуется. Сегодня стандарт — Vite (читается «вит», от французского «быстро»). Это инструмент сборки: он запускает dev-сервер, мгновенно обновляет страницу при сохранении файла и собирает проект для публикации.

Шаг 1. Проверяем Node.js

Vite работает на Node.js. Откройте терминал и проверьте версии (про npm мы говорили в уроке npm и package.json):

node -v
npm -v

Если команда не найдена — установите LTS-версию Node.js с официального сайта nodejs.org. Новым версиям Vite нужен свежий Node.js (20+ или новее), поэтому старый Node лучше обновить.

Шаг 2. Создаём проект

npm create vite@latest my-react-app -- --template react
  • npm create vite@latest — запускает свежую версию генератора проектов Vite;
  • my-react-app — название папки проекта;
  • -- --template react — шаблон «React + JavaScript». Для TypeScript есть шаблон react-ts, к нему вернёмся в уроке TypeScript.

Генератор может задать пару вопросов (например, «установить зависимости и запустить сейчас?»). Можно согласиться — или выполнить шаги вручную:

cd my-react-app
npm install
npm run dev

В терминале появится адрес вроде http://localhost:5173/. Откройте его в браузере — вы увидите стартовую страницу Vite + React со счётчиком.

Шаг 3. Смотрим структуру проекта

my-react-app/
├── node_modules/      ← установленные библиотеки (не трогаем, не коммитим)
├── public/            ← файлы «как есть» (favicon и т. п.)
├── src/               ← ваш код живёт здесь
│   ├── assets/        ← картинки, импортируемые из кода
│   ├── App.css
│   ├── App.jsx        ← главный компонент
│   ├── index.css      ← глобальные стили
│   └── main.jsx       ← точка входа
├── index.html         ← единственная HTML-страница
├── package.json       ← зависимости и скрипты
└── vite.config.js     ← настройки Vite

Скрипты в package.json:

Команда Что делает
npm run dev Запускает dev-сервер для разработки
npm run build Собирает готовый сайт в папку dist
npm run preview Показывает собранную версию локально

Как React попадает на страницу

Откройте index.html. Внутри почти пусто:

<body>
  <div id="root"></div>
  <script type="module" src="/src/main.jsx"></script>
</body>

Пустой div с id="root" — это «контейнер», в который React нарисует всё приложение. Теперь src/main.jsx:

import { StrictMode } from 'react';
import { createRoot } from 'react-dom/client';
import './index.css';
import App from './App.jsx';

createRoot(document.getElementById('root')).render(
  <StrictMode>
    <App />
  </StrictMode>
);

Разберём по строчкам:

  • import { StrictMode } from 'react' — берём из React специальный компонент-«строгий проверяющий». В режиме разработки он помогает находить ошибки (и иногда специально вызывает код дважды — это нормально).
  • import { createRoot } from 'react-dom/client' — react-dom связывает React с браузерным DOM.
  • import './index.css' — подключаем глобальные стили. Да, в проектах на Vite CSS можно импортировать прямо в JS.
  • import App from './App.jsx' — импортируем главный компонент.
  • createRoot(...) — создаём «корень» React внутри div#root.
  • .render(<App />) — говорим: «нарисуй здесь компонент App».

Получается цепочка: index.html → main.jsx → App.jsx → остальные компоненты.

Что такое JSX

Посмотрите на эту строку:

const title = <h1 className="title">Привет, React!</h1>;

Это не строка и не HTML. Это JSX — расширение синтаксиса JavaScript, которое позволяет писать разметку прямо в коде. Браузер JSX не понимает, поэтому Vite перед запуском превращает его в обычный JavaScript. Примерно так:

const title = React.createElement('h1', { className: 'title' }, 'Привет, React!');

Писать createElement вручную неудобно, поэтому все используют JSX. Файлы с JSX обычно называют с расширением .jsx.

Правила JSX

JSX похож на HTML, но у него есть строгие правила. Это частый источник ошибок у новичков.

1. Компонент возвращает один корневой элемент. Нельзя вернуть два соседних тега:

// ❌ Ошибка: два элемента рядом
return (
  <h1>Заголовок</h1>
  <p>Текст</p>
);

Оберните их в div или во фрагмент <>... — пустую обёртку, которая не попадает в DOM:

// ✅ Правильно
return (
  <>
    <h1>Заголовок</h1>
    <p>Текст</p>
  </>
);

2. Все теги закрываются. Даже те, что в HTML можно не закрывать:

<img src="/logo.svg" alt="Логотип" />
<input type="text" />
<br />

3. className вместо class. Слово class в JavaScript занято (классы ООП), поэтому:

<div className="card">Карточка</div>
<label htmlFor="email">Email</label>   {/* for → htmlFor */}

4. Атрибуты в camelCase. onclick → onClick, tabindex → tabIndex, maxlength → maxLength. Исключение — data-* и aria-*, они пишутся как в HTML.

5. style — это объект, а не строка. Свойства тоже в camelCase:

<p style={{ color: 'red', fontSize: '20px', marginTop: 10 }}>Важный текст</p>

Двойные фигурные скобки — это не особый синтаксис: внешние {} означают «здесь JavaScript», внутренние — обычный объект. Число 10 React сам превратит в 10px.

6. Комментарии пишутся внутри фигурных скобок: {/* комментарий */}.

Фигурные скобки: JavaScript внутри разметки

Внутри {} можно писать любое выражение JavaScript — то, что возвращает значение: переменную, вычисление, вызов функции, тернарный оператор.

function Profile() {
  const name = 'Айгерим';
  const age = 21;
  const avatar = 'https://example.com/avatar.png';

  function getGreeting() {
    const hour = new Date().getHours();
    return hour < 12 ? 'Доброе утро' : 'Добрый день';
  }

  return (
    <div className="profile">
      <img src={avatar} alt={name} width={80} />
      <h2>{getGreeting()}, {name}!</h2>
      <p>Через год вам будет {age + 1}</p>
      <p>Имя в верхнем регистре: {name.toUpperCase()}</p>
    </div>
  );
}

Разбор:

  • src={avatar} — значение атрибута берётся из переменной (без кавычек!). Кавычки — для обычных строк: alt="Фото".
  • {getGreeting()} — вызываем функцию, её результат появится в тексте.
  • {age + 1} — любое вычисление.
  • width={80} — число передаём в фигурных скобках.

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

Часто нужно показать элемент только при каком-то условии.

function Greeting() {
  const isLoggedIn = true;
  const unread = 3;

  // Способ 1: if до return
  if (!isLoggedIn) {
    return <p>Пожалуйста, войдите в аккаунт</p>;
  }

  return (
    <div>
      {/* Способ 2: тернарный оператор — «или то, или другое» */}
      <h1>{isLoggedIn ? 'С возвращением!' : 'Здравствуйте, гость'}</h1>

      {/* Способ 3: && — «показать, только если true» */}
      {unread > 0 && <p>У вас {unread} новых сообщения</p>}
    </div>
  );
}

Как работает &&: если левая часть ложна, React ничего не рисует; если истинна — рисует то, что справа.

Что React выводит, а что нет: строки и числа — показывает; null, undefined, true, false — ничего не показывает. Обычный объект {} вывести нельзя — будет ошибка «Objects are not valid as a React child».

Рендеринг компонентов

Первый компонент

Компонент в React — это обычная функция, которая возвращает JSX. Два правила:

  1. Имя начинается с большой буквы: Header, а не header. По этому признаку React отличает ваши компоненты от HTML-тегов.
  2. Функция возвращает разметку (или null, если показывать нечего).

Откройте src/App.jsx, удалите всё и напишите:

function Header() {
  return (
    <header>
      <h1>Мой первый сайт на React</h1>
    </header>
  );
}

function Footer() {
  const year = new Date().getFullYear();
  return <footer>© {year} Все права защищены</footer>;
}

function App() {
  return (
    <div>
      <Header />
      <main>
        <p>Здесь будет контент.</p>
      </main>
      <Footer />
    </div>
  );
}

export default App;

Сохраните файл — страница в браузере обновится сама. Это HMR (горячая перезагрузка) от Vite.

Разбор:

  • Header и Footer — маленькие компоненты, каждый отвечает за свой кусок страницы.
  • <Header /> — так компонент используется (рендерится). Это как свой собственный HTML-тег.
  • App — главный компонент, который собирает остальные. Его мы импортировали в main.jsx.
  • export default App — экспорт, чтобы main.jsx мог его импортировать. Подробно про импорт и экспорт — в уроке Компоненты и пропсы.
  • Круглые скобки после return нужны, когда JSX занимает несколько строк. Без них JavaScript может решить, что return пустой.

Что происходит при рендеринге

Рендеринг — это когда React вызывает вашу функцию-компонент, получает JSX и показывает результат на странице. Порядок такой:

  1. createRoot(...).render(<App />) — React вызывает функцию App.
  2. Внутри App есть <Header /> — React вызывает Header, и так вниз по дереву.
  3. Из всех результатов React строит DOM и вставляет его в #root.
  4. Когда данные изменятся, React снова вызовет нужные функции и обновит только изменённые части.

Поэтому компонент должен быть чистой функцией: при одинаковых данных возвращать одинаковый результат и не менять ничего снаружи во время рендера.

Типичные ошибки новичков

Ошибка Как выглядит Как исправить
Имя компонента с маленькой буквы function header() и <header /> function Header() и <Header />
class вместо className <div class="box"> <div className="box">
Незакрытый тег <img src="a.png"> <img src="a.png" />
Два корневых элемента return <h1/><p/> Обернуть во фрагмент <>...
style строкой style="color: red" style={{ color: 'red' }}
Вызов функции-компонента {Header()} <Header />
if внутри JSX {if (ok) ...} Тернарник или &&

Практика

  1. Новый проект. Создайте проект react-start через Vite, запустите npm run dev, очистите App.jsx и выведите заголовок «Привет, React!». Ожидаемый результат: на localhost:5173 только ваш заголовок.
  2. Визитка. Создайте компонент BusinessCard, который показывает имя, профессию, город и фото (через src={...} из переменной). Стили задайте через style={{ ... }}. Ожидаемый результат: карточка с данными из переменных, а не вписанными в разметку.
  3. Сборка страницы. Сделайте компоненты Header, Main, Footer и соберите их в App. В Footer выведите текущий год через new Date().getFullYear(). Ожидаемый результат: три части страницы, каждая — отдельный компонент.
  4. Условия. Создайте переменные isOnline (true/false) и messages (число). Если пользователь онлайн, покажите зелёную надпись «В сети», иначе серую «Не в сети». Блок «Новых сообщений: N» показывайте только если messages > 0. Проверьте, что при messages = 0 на странице не появляется ноль.
  5. Время суток. Компонент DayGreeting показывает «Доброе утро» / «Добрый день» / «Добрый вечер» / «Доброй ночи» в зависимости от текущего часа. Логику вынесите в функцию до return. Ожидаемый результат: правильное приветствие при перезагрузке страницы.

Итоги

  • React — библиотека для интерфейсов, где страница собирается из компонентов, как из деталей LEGO.
  • Новый проект создаётся командой npm create vite@latest имя -- --template react, запускается через npm run dev.
  • Цепочка запуска: index.html (div#root) → main.jsx (createRoot().render()) → App.jsx.
  • JSX — разметка внутри JavaScript: один корневой элемент, закрытые теги, className, style={{}}, camelCase.
  • В {} пишутся выражения; для условий — тернарник ? : и && (осторожно с нулём).
  • Компонент — функция с большой буквы, возвращающая JSX; используется как тег <Header />.
Отзыв