React с нуля: Быстрый старт в современной веб-разработке

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

1. Введение в экосистему React: JSX, Virtual DOM и создание первого проекта

Введение в экосистему React: JSX, Virtual DOM и создание первого проекта

Добро пожаловать на курс React с нуля. Если вы читаете эту статью, значит, вы решили освоить одну из самых востребованных технологий в мире веб-разработки. React — это не просто библиотека, это стандарт индустрии, который используют такие гиганты, как Facebook (Meta), Netflix, Airbnb и тысячи других компаний.

В этой первой лекции мы не будем просто писать код «вслепую». Мы разберем фундамент: почему React работает именно так, что такое «Виртуальный DOM» и почему мы пишем HTML внутри JavaScript. А в конце занятия мы создадим ваше первое современное приложение.

Что такое React и почему он победил?

React — это JavaScript-библиотека для создания пользовательских интерфейсов, разработанная компанией Facebook в 2013 году. Обратите внимание: это именно библиотека, а не фреймворк (как Angular). Это означает, что React отвечает только за «рисующую» часть приложения (View), давая вам свободу в выборе инструментов для маршрутизации или управления данными.

Главная идея React заключается в компонентном подходе. Представьте, что вы собираете конструктор LEGO. У вас есть маленькие детали: кирпичики, колеса, окна. Из них вы собираете машину. В веб-разработке:

* Кирпичик — это Компонент (кнопка, поле ввода, аватарка). * Машина — это Приложение (страница сайта).

!Визуализация компонентной архитектуры: страница состоит из вложенных друг в друга независимых блоков.

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

Virtual DOM: Магия производительности

Одной из самых сложных операций в браузере является работа с DOM (Document Object Model). DOM — это древовидная структура, описывающая вашу HTML-страницу. Когда вы меняете что-то на странице через обычный JavaScript (например, document.getElementById('id').innerHTML = ...), браузеру приходится проделывать огромную работу: пересчитывать стили, размеры элементов и перерисовывать страницу.

Если обновлений много, сайт начинает «тормозить». React решает эту проблему с помощью концепции Virtual DOM (Виртуальный DOM).

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

  • Копия: React хранит в памяти легкую копию реального DOM-дерева — это и есть Virtual DOM.
  • Изменение: Когда данные в приложении меняются, React создает новую версию Virtual DOM.
  • Сравнение (Diffing): React сравнивает старую версию Virtual DOM с новой. Этот процесс называется Reconciliation (согласование). Он находит минимальное количество отличий.
  • Обновление: React точечно обновляет только те части реального DOM, которые действительно изменились.
  • !Схема работы Virtual DOM: React вычисляет разницу между состояниями и обновляет только необходимые элементы реального DOM.

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

    JSX: HTML в вашем JavaScript

    Когда новички впервые видят код React, они часто удивляются. Это выглядит как HTML, смешанный с JavaScript. Этот синтаксис называется JSX (JavaScript XML).

    Посмотрите на пример:

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

    Почему JSX удобен?

  • Наглядность: Вы видите структуру интерфейса прямо в коде логики.
  • Безопасность: JSX предотвращает атаки типа XSS (межсайтовый скриптинг), автоматически экранируя вставляемые значения.
  • Мощь JavaScript: Внутри JSX можно использовать любые выражения JavaScript, обернув их в фигурные скобки {}.
  • Пример использования переменной:

    Важные правила JSX

    Поскольку JSX — это всё-таки JavaScript, есть несколько отличий от HTML:

    * Один родитель: Компонент должен возвращать только один корневой элемент. Если нужно вернуть несколько, оберните их в <div> или пустой фрагмент <>...</>. * camelCase: Атрибуты пишутся в верблюжьем регистре. Например, вместо onclick пишем onClick. * className: Слово class зарезервировано в JavaScript, поэтому для CSS-классов используется атрибут className.

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

    Раньше стандартом для создания проектов был инструмент create-react-app. Однако сейчас индустрия перешла на более быстрые и современные инструменты. Мы будем использовать Vite (читается как «Вит», с французского «быстро»).

    Шаг 1: Подготовка окружения

    Для работы React вам понадобится Node.js. Это среда выполнения JavaScript вне браузера. Если она у вас не установлена, скачайте LTS-версию с официального сайта Node.js.

    Вместе с Node.js установится npm (Node Package Manager) — менеджер пакетов, который позволит нам скачивать библиотеки.

    Шаг 2: Инициализация проекта

    Откройте терминал (командную строку) и перейдите в папку, где хотите создать проект. Введите команду:

    Где my-first-react-app — название вашей папки с проектом.

    После выполнения команды, перейдите в папку и установите зависимости:

    Теперь запустите проект:

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

    Разбор структуры проекта

    Давайте откроем папку проекта в редакторе кода (рекомендую VS Code) и посмотрим, что внутри.

    Основные файлы

  • index.html: Это единственная HTML-страница вашего приложения. В ней есть важный элемент: <div id="root"></div>. Именно сюда React будет «встраивать» всё ваше приложение.
  • src/main.jsx: Это «точка входа» JavaScript. Здесь мы говорим React: «Возьми компонент App и помести его внутрь элемента с id root».
  • src/App.jsx: Это ваш главный компонент. Сейчас там находится код, который вы видите на экране браузера.
  • Ваше первое изменение

    Давайте очистим App.jsx от лишнего и напишем свой код. Удалите всё содержимое файла и вставьте следующее:

    Сохраните файл. Браузер обновится автоматически, и вы увидите свой текст. Вы только что создали свой первый React-компонент!

    Заключение

    Сегодня мы заложили фундамент. Мы узнали, что React использует Virtual DOM для скорости, компоненты для повторного использования кода и JSX для удобного описания интерфейса. Мы также настроили современное окружение с помощью Vite.

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

    > «Любая достаточно развитая технология неотличима от магии». — Артур Кларк. Законы Кларка

    Для React этой «магией» является Virtual DOM, но теперь вы знаете секрет фокуса.

    2. Архитектура приложения: функциональные компоненты, пропсы и композиция интерфейса

    Архитектура приложения: функциональные компоненты, пропсы и композиция интерфейса

    В предыдущей лекции мы создали наше первое React-приложение и познакомились с JSX. Сейчас наш проект выглядит просто: один файл App.jsx, в котором написан весь код. Это нормально для «Hello World», но представьте, что вы создаете аналог Facebook или YouTube. Если писать весь код в одном файле, он растянется на сотни тысяч строк, и поддерживать его станет невозможно.

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

    Функциональные компоненты: Строительные блоки

    В современном React компоненты — это просто JavaScript-функции. Да, именно так. Если вы знаете, как написать функцию, вы уже на 90% знаете, как написать компонент.

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

    Давайте посмотрим на простейший компонент:

    Здесь есть два критически важных правила, которые отличают компонент от обычной функции:

  • Название с большой буквы. React требует, чтобы имена компонентов начинались с заглавной буквы (например, Welcome, а не welcome). Это нужно, чтобы отличать их от обычных HTML-тегов (<div>, <span>).
  • Возврат JSX. Функция должна возвращать разметку, которую нужно отрисовать.
  • !Визуализация того, как страница разбивается на независимые компоненты.

    Принцип единственной ответственности

    Хорошая архитектура строится на принципе Single Responsibility (Единственная ответственность). Каждый компонент должен делать что-то одно, но делать это хорошо.

    * Button — просто рисует кнопку. * Header — рисует шапку сайта. * UserProfile — отображает информацию о пользователе.

    Если ваш компонент занимает 500 строк кода, скорее всего, его пора разбить на подкомпоненты.

    Пропсы (Props): Передача данных

    Компонент Welcome, который мы написали выше, статичен. Он всегда выводит «Добро пожаловать!». Но что, если мы хотим поприветствовать конкретного пользователя? В обычных функциях мы используем аргументы. В React мы используем Props (сокращение от properties — свойства).

    Как передать пропсы?

    Пропсы передаются компоненту так же, как атрибуты HTML-тегам:

    Как принять пропсы?

    React собирает все переданные атрибуты в один объект и передает его первым аргументом в функцию-компонент.

    Деструктуризация пропсов

    В современном коде редко пишут props.name. Гораздо удобнее использовать деструктуризацию объектов JavaScript сразу в параметрах функции. Это делает код чище и понятнее:

    !Однонаправленный поток данных: пропсы передаются только от родителя к ребенку.

    Главное правило пропсов

    Пропсы доступны только для чтения (Read-Only).

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

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

    Композиция: Собираем LEGO

    Композиция — это вкладывание одних компонентов в другие. Именно так строится всё приложение: от маленьких кнопок до целых страниц.

    Давайте создадим карточку профиля пользователя, используя композицию.

    Сначала создадим маленькие компоненты:

    Теперь соберем их в компонент побольше — UserCard:

    И наконец, используем UserCard в главном приложении App:

    Такой подход делает код читаемым. Глядя на UserCard, мы сразу понимаем его структуру, не отвлекаясь на детали реализации того, как именно рисуется картинка или текст.

    Специальный пропс: children

    Иногда мы не знаем заранее, что будет внутри компонента. Представьте, что вы создаете красивую рамку BorderBox. Внутри неё может быть текст, картинка или другой компонент.

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

    Определение компонента-обертки:

    Использование:

    В этом примере <h1> и <p> попадут в пропс children компонента BorderBox и будут отрисованы внутри div с классом fancy-border.

    Организация файлов проекта

    В реальном проекте мы не пишем все компоненты в одном файле. Стандартная практика — один компонент = один файл.

    Давайте реорганизуем структуру нашего проекта из прошлой лекции.

  • В папке src создайте папку components.
  • Создайте файл src/components/Header.jsx.
  • Теперь подключим его в App.jsx:
  • Обратите внимание на ключевые слова export default и import. Это модульная система JavaScript (ES Modules), которая позволяет разбивать код на файлы.

    Практические советы по архитектуре

  • Начинайте с малого. Не пытайтесь сразу продумать всю иерархию. Начните с больших блоков, а по мере усложнения кода выделяйте повторяющиеся части в отдельные компоненты.
  • Держите компоненты чистыми. Старайтесь не смешивать логику получения данных и логику отображения (об этом мы поговорим подробнее в следующих статьях).
  • Имена имеют значение. Называйте компоненты так, чтобы по имени было понятно, что они делают (SubmitButton, ProductList, Navigation).
  • Заключение

    Сегодня мы сделали огромный шаг вперед. Мы перешли от написания простого HTML в JS к созданию настоящей архитектуры приложения. Мы узнали:

    * Функциональные компоненты — это функции, возвращающие JSX. * Пропсы — это способ передать данные от родителя к ребенку (сверху вниз). * Композиция — это метод сборки сложных интерфейсов из простых блоков. * children — способ передачи контента внутрь компонента-обертки.

    Теперь наши компоненты умеют отображать данные, но они всё еще статичны. Они не умеют реагировать на действия пользователя, например, менять цвет кнопки при нажатии или обновлять счетчик. Чтобы оживить их, нам нужно познакомиться с понятием Состояние (State). Именно этому будет посвящена следующая статья.

    > «Простота — залог надежности». — Эдсгер Дейкстра, ученый в области компьютерных наук.

    3. Интерактивность и логика: управление состоянием через useState и обработка событий

    Интерактивность и логика: управление состоянием через useState и обработка событий

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

    Проблема заключается в том, что пропсы доступны только для чтения. Компонент не может изменить свои пропсы, так же как вы не можете изменить сюжет напечатанной книги. Чтобы сделать интерфейс живым, нам нужен новый инструмент — Состояние (State).

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

    Обработка событий: Слушаем пользователя

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

    В React обработка событий очень похожа на стандартный HTML, но с двумя важными отличиями:

  • Названия событий пишутся в верблюжьем регистре (camelCase): onclick превращается в onClick, onchange — в onChange.
  • Вместо строки с кодом вы передаете саму функцию-обработчик.
  • Посмотрите на разницу:

    Самая частая ошибка новичков

    Обратите внимание на отсутствие круглых скобок () после названия функции в примере React. Это критически важный момент.

    Правильно: onClick={handleClick}. Вы передаете* функцию React'у. Он вызовет её сам, когда произойдет клик. Неправильно: onClick={handleClick()}. Вы вызываете* функцию немедленно при отрисовке компонента. Это может привести к бесконечному циклу перерисовок или ошибкам.

    Вы также можете объявлять обработчики прямо внутри JSX, используя стрелочные функции:

    Введение в хуки: useState

    Теперь, когда мы умеем ловить клики, давайте попробуем изменить данные. Допустим, мы хотим сделать счетчик лайков.

    Если мы попробуем использовать обычную переменную, ничего не выйдет:

    Почему это не работает? Потому что React не знает, что переменная count изменилась. Он отрисовал компонент один раз и «забыл» про него. Чтобы React обновил интерфейс, нужно сообщить ему об изменениях. Для этого используется State.

    Для работы с состоянием в функциональных компонентах используется специальная функция (хук) — useState.

    Анатомия useState

    Хук useState импортируется из библиотеки react:

    Синтаксис выглядит так:

    Давайте разберем эту строку по частям:

  • initialValue: Начальное значение состояния (например, 0 для счетчика или "" для текста).
  • state: Переменная, которая хранит текущее значение.
  • setState: Функция, которая позволяет изменить значение и заставляет React перерисовать компонент.
  • [...]: Это деструктуризация массива. useState всегда возвращает массив из двух элементов, и мы сразу присваиваем им имена.
  • !Циклический процесс обновления интерфейса: действие пользователя запускает изменение состояния, которое вызывает перерисовку компонента.

    Исправляем счетчик

    Теперь перепишем наш счетчик, используя useState:

    Теперь при каждом клике:

  • Вызывается setCount.
  • React понимает, что данные изменились.
  • React заново запускает функцию Counter.
  • useState возвращает уже новое значение count.
  • Интерфейс обновляется.
  • Правила использования хуков

    Хуки (функции, начинающиеся с use, например useState) — это мощный инструмент, но у них есть строгие правила, которые нельзя нарушать, иначе магия React сломается.

  • Только на верхнем уровне: Не вызывайте хуки внутри циклов, условий (if) или вложенных функций. Они всегда должны быть в начале тела компонента.
  • Только в React-функциях: Вызывайте хуки только внутри функциональных компонентов React или внутри других пользовательских хуков.
  • Работа со сложным состоянием

    Состояние не обязательно должно быть числом или строкой. Это может быть объект или массив. Однако здесь есть важный нюанс: иммутабельность (неизменяемость).

    В React нельзя менять объекты состояния напрямую. Вы должны всегда создавать новую копию объекта.

    Пример с объектом

    Представьте форму профиля пользователя:

    Если мы хотим изменить только город, нельзя делать так:

    Вместо этого мы должны создать новый объект, скопировав старые данные и заменив нужные поля. Для этого идеально подходит оператор расширения (spread operator) ...:

    Управляемые компоненты (Forms)

    В традиционном HTML элементы форм (input, textarea, select) сами хранят свое состояние. В React принято держать состояние в компоненте, а не в DOM. Такие элементы называются управляемыми компонентами (Controlled Components).

    Мы связываем значение инпута (value) с состоянием React и обновляем состояние при каждом вводе символа (onChange).

    Этот подход дает вам полный контроль. Вы можете мгновенно валидировать ввод, форматировать его (например, превращать в верхний регистр) или блокировать запрещенные символы.

    Изоляция состояния

    Важно понимать, что состояние привязано к конкретному экземпляру компонента, а не к самой функции.

    Если вы отрендерите компонент Counter дважды, у каждого из них будет свой собственный, независимый счетчик.

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

    Заключение

    Сегодня мы оживили наше приложение. Мы узнали, что:

    * События в React требуют передачи функции, а не её вызова. * useState — это хук, который позволяет компонентам «запоминать» данные между отрисовками. * Изменение состояния через функцию set... — единственный способ заставить React обновить интерфейс. * При работе с объектами важно соблюдать принцип иммутабельности.

    Теперь наши компоненты могут реагировать на пользователя. Но что, если нам нужно взаимодействовать с внешним миром? Загружать данные с сервера, устанавливать таймеры или подписываться на события браузера? Для этого нам понадобится следующий фундаментальный хук — useEffect, который мы разберем в следующей статье.

    > «Программы должны писаться для людей, которые будут их читать, и только во вторую очередь для машин, которые будут их выполнять». — Гарольд Абельсон.

    4. Работа с внешним миром: хук useEffect, жизненный цикл и запросы к API

    Работа с внешним миром: хук useEffect, жизненный цикл и запросы к API

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

    В реальной разработке приложение постоянно общается с внешним миром: запрашивает список товаров, проверяет авторизацию пользователя или отслеживает изменение размера экрана. В React для выполнения всех этих действий существует специальный инструмент — хук useEffect.

    Сегодня мы разберем, что такое «побочные эффекты», как управлять жизненным циклом компонента и как правильно делать запросы к API.

    Чистые функции и побочные эффекты

    Чтобы понять useEffect, нужно вспомнить концепцию из функционального программирования.

    React стремится к тому, чтобы компоненты были чистыми функциями (Pure Functions). Это означает, что при одних и тех же входных данных (пропсах) компонент должен всегда возвращать один и тот же результат (JSX) и ничего не менять за пределами своей области видимости.

    Однако реальные приложения не могут быть абсолютно чистыми. Нам нужно: * Запросить данные с сервера. * Изменить заголовок вкладки браузера (document.title). * Установить таймер (setInterval). * Повесить слушатель на прокрутку страницы.

    Все эти действия называются побочными эффектами (Side Effects), потому что они влияют на что-то за пределами самого компонента. Хук useEffect — это официальное место в React, куда мы помещаем все побочные эффекты.

    Синтаксис useEffect

    Хук принимает два аргумента:

  • Функция-эффект: код, который нужно выполнить.
  • Массив зависимостей (опционально): список переменных, при изменении которых эффект должен сработать снова.
  • Самое важное в useEffect — понять, когда он запускается. Это регулируется вторым аргументом.

    !Визуализация трех режимов работы useEffect в зависимости от переданного массива зависимостей.

    1. Без массива зависимостей

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

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

    2. Пустой массив зависимостей []

    Если передать пустой массив, React запомнит, что у эффекта нет зависимостей от пропсов или состояния. Поэтому он запустит его только один раз — сразу после того, как компонент впервые появится на экране (этот момент называется Mounting или Монтирование).

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

    3. Массив с переменными [value]

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

    Жизненный цикл компонента

    В старых версиях React (на классах) существовали методы жизненного цикла: componentDidMount, componentDidUpdate, componentWillUnmount. Хук useEffect объединяет их все в единый API.

    Давайте рассмотрим полный цикл жизни компонента на примере чата.

    Функция очистки (Cleanup)

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

    Для этого функция-эффект может вернуть другую функцию — функцию очистки.

    React вызовет функцию очистки в двух случаях:

  • Перед тем, как компонент будет удален со страницы (Unmount).
  • Перед тем, как эффект будет перезапущен (если изменились зависимости).
  • Работа с API: Загрузка данных

    Самый частый сценарий использования useEffect — получение данных с бэкенда. Рассмотрим классический паттерн загрузки данных.

    Нам понадобятся три состояния:

  • data: для хранения результата.
  • isLoading: для отображения спиннера загрузки.
  • error: для обработки ошибок.
  • Почему нельзя сделать useEffect(async () => ...)?

    Вы могли заметить, что мы создали функцию fetchData внутри эффекта, а не сделали саму функцию эффекта асинхронной.

    Это важное правило: функция, передаваемая в useEffect, не может быть асинхронной.

    Дело в том, что async функция всегда возвращает Промис (Promise), а React ожидает, что эффект вернет либо ничего (undefined), либо функцию очистки. Если вернуть Промис, React не сможет выполнить очистку, и это приведет к ошибкам.

    Распространенные ошибки

    1. Отсутствие зависимостей

    Новички часто забывают добавить переменную в массив зависимостей, хотя используют её внутри эффекта. Современные линтеры (ESLint) обычно предупреждают об этом. Всегда слушайте линтер!

    2. Бесконечный цикл запросов

    В этом примере компонент рендерится -> запускается эффект -> обновляется стейт -> компонент рендерится -> запускается эффект... Это DDoS-атака на ваш собственный сервер.

    3. Условия внутри хуков

    Как и useState, useEffect нельзя вызывать внутри условий if или циклов. Хуки всегда должны быть на верхнем уровне функции.

    Заключение

    Хук useEffect — это мощный инструмент, который синхронизирует ваш React-компонент с внешними системами.

    Мы узнали, что: * Массив зависимостей управляет частотой запуска эффекта. * Пустой массив [] означает «запустить один раз при монтировании». * Функция очистки помогает избежать утечек памяти. * Для работы с API нужно использовать комбинацию useEffect и useState для отслеживания статуса загрузки.

    Теперь вы умеете создавать полноценные приложения, которые не просто отображают статику, но и взаимодействуют с реальными данными. В следующей статье мы поговорим о том, как создавать собственные хуки (Custom Hooks), чтобы переиспользовать логику между компонентами и делать код чище.

    > «С большой силой приходит большая ответственность». — Принцип Питера Паркера, который отлично применим к использованию useEffect и бесконечным циклам.

    5. Продвинутые техники: маршрутизация с React Router и управление глобальным контекстом

    Продвинутые техники: маршрутизация с React Router и управление глобальным контекстом

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

    Кроме того, по мере роста приложения вы могли заметить проблему: передавать данные через пропсы через 5-6 уровней компонентов становится утомительно. Это явление называется Prop Drilling (сверление пропсов).

    В этой статье мы решим обе проблемы. Мы превратим наше приложение в полноценный многостраничный сайт с помощью React Router и научимся телепортировать данные в любую точку приложения с помощью Context API.

    Маршрутизация на стороне клиента (SPA)

    Традиционные сайты работают так: вы кликаете на ссылку, браузер отправляет запрос на сервер, сервер собирает новую HTML-страницу и отправляет её обратно. Страница перезагружается, экран мигает белым.

    React использует другой подход — Single Page Application (SPA). В SPA у нас есть только один HTML-файл (index.html). Когда пользователь кликает на ссылку, JavaScript перехватывает это действие, меняет URL в адресной строке и подменяет компоненты на странице. Перезагрузки не происходит. Это работает мгновенно.

    !В SPA сервер отдает страницу только один раз, дальше навигацией управляет JavaScript.

    Установка React Router

    React не имеет встроенного роутера. Самым популярным решением является библиотека react-router-dom. Установим её:

    Настройка маршрутов

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

    Теперь в App.jsx мы можем определить маршруты:

    Почему Link, а не <a>?

    Если вы используете обычный тег <a href="/about">, браузер выполнит стандартный переход с перезагрузкой страницы. Всё состояние вашего приложения (переменные, данные форм) сбросится.

    Компонент Link внутри себя использует History API браузера, чтобы изменить URL без перезагрузки.

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

    Часто нам нужны страницы вида /users/1, /users/42, где число — это ID пользователя. В React Router для этого используется двоеточие:

    Внутри компонента UserProfile мы можем получить этот ID с помощью хука useParams:

    Управление глобальным состоянием: Context API

    Представьте, что у вас есть данные о текущем пользователе (имя, аватарка) в компоненте App. А отобразить аватарку нужно в компоненте Header, который внутри Layout, который внутри App. А еще имя нужно в Settings, который глубоко внутри Dashboard.

    Вам придется передавать проп user через все промежуточные компоненты, даже если они им не пользуются. Это и есть Prop Drilling.

    !Context API позволяет передавать данные напрямую, минуя промежуточные звенья.

    Решение — Context API. Это способ создать «глобальную переменную», доступную для любого компонента в дереве.

    Шаг 1: Создание контекста

    Создадим отдельный файл UserContext.js:

    Шаг 2: Провайдер (Provider)

    Нам нужно обернуть часть приложения, которая должна иметь доступ к данным, в компонент Provider. Обычно это делается в App.jsx.

    Шаг 3: Потребление (Consumer)

    Теперь в любом вложенном компоненте (например, в Header) мы можем получить данные без пропсов:

    Когда использовать Context?

    Контекст — мощный инструмент, но не стоит злоупотреблять им. Используйте его для данных, которые действительно «глобальные»:

    * Тема оформления (светлая/темная). * Данные авторизованного пользователя. * Язык интерфейса (локализация). * Глобальные настройки приложения.

    Для локальных данных (например, состояние формы или открыт ли конкретный выпадающий список) лучше использовать обычный useState.

    Заключение

    Сегодня мы превратили набор разрозненных компонентов в полноценное приложение.

  • React Router позволил нам создать навигацию и структуру страниц без перезагрузки браузера.
  • Context API избавил нас от необходимости прокидывать пропсы через десятки компонентов, позволив «телепортировать» данные туда, где они нужны.
  • Теперь вы владеете полным набором инструментов для создания сложных React-приложений. В следующей, заключительной статье курса, мы поговорим о том, как оптимизировать наше приложение и подготовить его к публикации в интернете (деплою).

    > «Простые вещи должны быть простыми, а сложные — возможными». — Алан Кей, пионер объектно-ориентированного программирования.