React с нуля: от вёрстки до React Query и архитектуры

Практический курс по созданию современного приложения, охватывающий вёрстку интерфейса, маршрутизацию и управление состоянием через Redux Toolkit. Вы научитесь работать с API используя Axios и React Query, а в завершении проведете полный рефакторинг проекта по индустриальным стандартам.

1. Основы и вёрстка: Создание компонентов и UI-структуры приложения

Основы и вёрстка: Создание компонентов и UI-структуры приложения

Добро пожаловать в курс «React с нуля». Мы пройдем путь от создания первого файла до архитектурно сложного приложения с кэшированием данных и глобальным стейт-менеджментом. Но любой сложный механизм начинается с простых деталей. В React такими деталями являются компоненты.

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

Смена парадигмы: от страниц к компонентам

В классической веб-разработке мы привыкли мыслить страницами: index.html, about.html, contact.html. В React мы мыслим компонентами. Страница — это не монолитный файл, а дерево вложенных друг в друга элементов.

Согласно документации Next.js, пользовательские интерфейсы можно разбить на небольшие строительные блоки, называемые компонентами, которые позволяют создавать самодостаточные, повторно используемые фрагменты кода.

Представьте, что вы собираете конструктор LEGO. У вас есть кубики разных цветов и размеров. Из одних и тех же кубиков можно собрать замок, машину или космический корабль. В React:

* Кубик — это компонент (Кнопка, Карточка товара, Хедер). * Инструкция по сборке — это ваш код, который говорит, в каком порядке эти компоненты отображать.

Почему это эффективно?

  • Переиспользуемость. Вы пишете код кнопки один раз и используете её в 50 местах. Если нужно изменить цвет кнопки, вы меняете его в одном файле, и он меняется везде.
  • Изоляция. Логика одного компонента не ломает другой. Если сломалась «Корзина», «Хедер» продолжит работать.
  • Декларативность. Вы описываете, что хотите видеть, а React берет на себя задачу по обновлению DOM-дерева браузера.
  • Настройка окружения: Vite вместо CRA

    Долгое время стандартом был create-react-app (CRA), но сейчас индустрия перешла на Vite. Он быстрее, легче и современнее. Для начала работы вам понадобится Node.js.

    Откройте терминал и выполните команду:

    После запуска вы увидите локальный адрес (обычно http://localhost:5173). Это ваш сервер разработки. Все изменения в коде будут мгновенно отображаться в браузере.

    JSX: HTML в JavaScript

    Открыв файл App.jsx, вы увидите синтаксис, который выглядит как HTML, но находится внутри JavaScript-файла. Это JSX (JavaScript XML).

    Ключевые правила JSX

  • Вложенность. Компонент должен возвращать один родительский элемент. Если вам не нужен лишний div в DOM-дереве, используйте Фрагмент: <> ... </>.
  • Закрытие тегов. Все теги должны быть закрыты. Даже одиночные: <img />, <input />, <br />.
  • Атрибуты. Поскольку class — это зарезервированное слово в JS, в JSX используется className. Свойства из нескольких слов пишутся в camelCase: tabIndex, onClick.
  • Интерполяция JavaScript

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

    Внутри {} может быть любое валидное JS-выражение: переменная, функция, математическая операция или тернарный оператор. Единственное ограничение — там не может быть инструкций вроде if или for (но их можно заменить на тернарные операторы и методы массивов).

    Анатомия компонента

    В современном React компоненты — это обычные функции. Они принимают данные (props) и возвращают JSX.

    Создание первого компонента

    Давайте создадим структуру нашего проекта. В папке src создайте папку components. Внутри создадим файл Header.jsx.

    > В React компоненты — это функции. Внутри тега script создайте новую функцию header. > > Next.js Русский

    Важно: Название функции компонента обязательно должно начинаться с большой буквы. Это позволяет React отличать ваши компоненты от встроенных HTML-тегов (<Header /> против <header>).

    Файл src/components/Header.jsx:

    Теперь подключим его в главном файле App.jsx:

    Props: Передача данных

    Компоненты были бы бесполезны, если бы они всегда рендерили одно и то же. Чтобы сделать их динамическими, мы используем Props (пропсы). Это аргументы функции-компонента.

    Создадим карточку товара ProductCard.jsx:

    Проп children

    Существует специальный проп children. Он содержит всё, что вы передаете между открывающим и закрывающим тегом вашего компонента. Это полезно для создания компонентов-оберток (Layouts, Modals, Cards).

    Рендеринг списков

    В реальных приложениях данные приходят массивами. В React для вывода списков используется метод массива .map().

    Предположим, у нас есть массив данных (в будущем он придет из API через axios, но пока захардкодим его):

    Выведем их в App.jsx:

    Зачем нужен key?

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

    Стилизация и CSS

    React не навязывает способ стилизации. Вы можете использовать:

  • Обычный CSS: Просто импортируйте файл import './App.css'. Глобальная область видимости (может привести к конфликтам имен).
  • CSS Modules: Файлы вида App.module.css. Классы автоматически получают уникальные хеши, что предотвращает конфликты. Это предпочтительный вариант для чистого React.
  • CSS-in-JS / Utility classes: (Styled Components, Tailwind CSS) — рассмотрим в будущих статьях при рефакторинге.
  • Для текущего этапа достаточно создать App.css и задать базовую сетку:

    Итоги

    Мы заложили фундамент нашего приложения. Теперь у нас есть понимание того, как строится интерфейс в React.

  • Компоненты — это функции, которые возвращают JSX-разметку. Они должны начинаться с заглавной буквы.
  • JSX требует соблюдения правил: один родительский элемент (или фрагмент), закрытые теги, className вместо class.
  • Props позволяют передавать данные от родителя к ребенку. Поток данных всегда однонаправленный (сверху вниз).
  • Для вывода списков используется метод .map(), при этом каждому элементу необходим уникальный проп key.
  • Структура проекта должна быть модульной: разбивайте интерфейс на мелкие, независимые части.
  • В следующей статье мы оживим наше приложение, добавив ему состояние (State) и научимся обрабатывать события (клики, ввод данных).

    2. Роутинг и логика: Настройка React Router и интерактивность

    Роутинг и логика: Настройка React Router и интерактивность

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

    Сегодня мы вдохнем жизнь в наш проект. Мы разберем два фундаментальных столпа современной frontend-разработки: состояние (State) для интерактивности и маршрутизацию (Routing) для навигации. Мы превратим набор разрозненных компонентов в полноценное SPA (Single Page Application).

    Интерактивность: От статики к динамике

    В классическом JavaScript мы привыкли манипулировать DOM-деревом напрямую: находим элемент через querySelector, меняем ему innerHTML или класс. В React этот подход запрещен. React использует декларативную модель: вы меняете данные, а React сам обновляет интерфейс.

    Эту концепцию можно описать формулой:

    где — это пользовательский интерфейс (то, что мы видим на экране), — это ваша функция-компонент (логика отображения), а — это состояние (данные приложения в текущий момент времени). Если меняется , автоматически пересчитывается и .

    Хук useState

    Чтобы компонент мог «запоминать» данные и реагировать на их изменения, используется специальная функция (хук) — useState.

    Рассмотрим пример. Допустим, у нас есть кнопка «Купить», которая должна менять текст на «В корзине» после нажатия.

    Важные правила работы со стейтом:

  • Неизменяемость. Никогда не меняйте стейт напрямую (isAdded = true). Это не сработает, так как React не узнает об изменении. Используйте только функцию-сеттер (setIsAdded).
  • Изоляция. Каждый экземпляр компонента имеет свой собственный стейт. Если вы отрендерите десять кнопок BuyButton, нажатие на одну не повлияет на остальные.
  • Что такое SPA и Client-Side Routing?

    Теперь, когда наши компоненты умеют реагировать на действия пользователя, нам нужно связать их в единое приложение с несколькими страницами (Главная, Каталог, Страница товара).

    В традиционных сайтах при клике на ссылку браузер отправляет запрос на сервер, скачивает новый HTML-файл и полностью перезагружает страницу. Это долго и «мигает» белым экраном.

    В React используется подход SPA (Single Page Application). Приложение загружается один раз. При переходе по ссылке JavaScript просто подменяет одни компоненты на другие, не перезагружая страницу целиком.

    Согласно документации: > Маршрутизация на стороне клиента позволяет нам обновлять URL в браузере без дополнительных запросов документа с сервера. > > code.mu

    Для реализации этого в экосистеме React стандартом является библиотека React Router.

    Установка и настройка React Router

    Для начала установим библиотеку. В терминале вашего проекта выполните:

    На момент написания курса актуальны версии v6 и v7. Мы будем использовать стабильные паттерны, совместимые с обеими версиями, так как v7 является развитием идей v6.

    Подключение провайдера

    Чтобы роутинг заработал, нам нужно обернуть все наше приложение в компонент BrowserRouter. Обычно это делается в файле main.jsx (или index.js).

    Определение маршрутов

    Теперь в App.jsx мы можем определить, какой компонент показывать по какому адресу. Для этого используются компоненты Routes и Route.

    * path="/" — это главная страница. path="" — это специальный шаблон, который ловит все несуществующие адреса (аналог 404 ошибки).

    Навигация: Link вместо тега a

    Самая частая ошибка новичков — использование обычного тега <a> для переходов внутри приложения.

    Для SPA-переходов React Router предоставляет компонент Link.

    Как отмечают в сообществе: > Декларативные маршруты React являются компонентами и используют ту же инфраструктуру, что и любое приложение React. Эти маршруты связывают веб-адреса с определенными страницами. > > ru.hexlet.io

    Динамические маршруты и параметры

    Представьте интернет-магазин. Мы не можем создать отдельный файл Route для каждого из тысяч товаров. Нам нужен шаблон. В React Router для этого используются динамические параметры, обозначаемые двоеточием.

    Изменим наш App.jsx:

    Теперь этот маршрут сработает для /product/1, /product/abc, /product/555.

    Хук useParams

    Чтобы узнать, какой именно id был в строке браузера, внутри компонента ProductPage мы используем хук useParams.

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

    > Типизированная навигация превращает строковые пути в типизированные объекты. Вместо /admin/products/123/edit программист работает с функциями, которые знают структуру приложения. > > tproger.ru

    Хотя полная типизация маршрутов — тема продвинутого уровня, важно помнить: всегда проверяйте имена параметров в path и при деструктуризации в useParams.

    Вложенные маршруты и Layout (Outlet)

    В большинстве приложений есть общие части интерфейса: шапка (Header) и подвал (Footer), которые должны оставаться на месте при смене страниц. Раньше их приходилось вставлять в каждый компонент страницы. В современном React Router есть элегантное решение — Layout и компонент <Outlet />.

    Создадим компонент-обертку MainLayout.jsx:

    Теперь настроим вложенность в App.jsx:

    Теперь HomePage, CatalogPage и ProductPage будут автоматически рендериться внутри MainLayout вместо Outlet. Это значительно упрощает поддержку кода и избавляет от дублирования.

    Программная навигация: useNavigate

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

    Для этого используется хук useNavigate.

    Продвинутые возможности (краткий обзор)

    React Router постоянно развивается. Версия 7 (и поздняя 6.4+) привнесла новые возможности по загрузке данных (Loaders) и управлению ошибками.

    Согласно источнику: > React Router v7 предлагает элегантные решения этих проблем при правильном использовании... мы реорганизовали структуру роутинга, используя возможности этой библиотеки: избавились от лишних «букав кода». > > habr.com

    Однако для начала пути (и для большинства стандартных задач) классического подхода с useEffect (который мы изучим в следующей статье про API) и описанных выше компонентов Routes/Route более чем достаточно. Это база, на которой строится всё остальное.

    Итоги

    Мы превратили статический макет в работающее приложение. Теперь вы можете создавать сложные структуры страниц и интерактивные элементы.

  • Интерактивность через State: Используйте useState для данных, которые меняются во времени. Помните формулу , где — интерфейс, — компонент, — данные. Изменение стейта вызывает перерисовку компонента.
  • SPA Навигация: Используйте BrowserRouter и Routes для настройки путей. Это позволяет менять контент без перезагрузки страницы.
  • Ссылки: Забудьте про тег <a>. Используйте компонент <Link to="..."> для переходов внутри приложения.
  • Динамика: Используйте параметры в URL (:id) и хук useParams для создания шаблонных страниц (например, карточек товаров).
  • Структура: Используйте <Outlet /> для создания общих макетов (Layouts) с хедером и футером.
  • В следующей статье мы подключим наше приложение к реальному серверу, научимся получать данные через API с помощью Axios и обрабатывать побочные эффекты.