React для Angular-разработчиков: Быстрый старт

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

1. Основы React: JSX, Виртуальный DOM и ключевые отличия от шаблонов Angular

Основы React: JSX, Виртуальный DOM и ключевые отличия от шаблонов Angular

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

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

1. JSX: Это не просто HTML в JavaScript

Первое, что бросается в глаза при взгляде на код React — это странная смесь HTML-тегов прямо внутри JavaScript-кода. Это называется JSX (JavaScript XML).

В Angular мы привыкли к разделению ответственности: логика живет в файле .ts, а разметка — в файле .html. Angular парсит ваши шаблоны и превращает их в инструкции JavaScript во время компиляции.

В React философия другая: разметка и логика неразрывно связаны, поэтому они живут вместе внутри компонента. React считает, что логика рендеринга (как отобразить список, что показать при условии true) — это тоже часть UI-логики.

Как это работает под капотом?

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

Взгляните на этот пример:

Поскольку JSX — это JavaScript, вы можете использовать всю мощь языка прямо внутри разметки. Вам не нужно учить специальный синтаксис шаблонов (как ngIf или ngFor), вы просто используете операторы JavaScript.

!Визуализация процесса транспиляции JSX в нативный JavaScript

2. От шаблонов Angular к логике React

Давайте сравним, как решаются типовые задачи в Angular и React. Это поможет вам быстрее переключить контекст.

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

В Angular мы используем структурную директиву *ngIf:

В React мы используем обычные операторы JavaScript, такие как тернарный оператор или логическое И (&&):

Обратите внимание на фигурные скобки {}. В JSX они означают: «здесь начинается зона JavaScript». Все, что внутри скобок, будет вычислено.

Списки и циклы

В Angular есть *ngFor:

В React мы используем метод массива .map(), который возвращает новый массив элементов:

> Важное замечание: атрибут key в React обязателен при рендеринге списков. Он помогает React определять, какие элементы были изменены, добавлены или удалены. Это аналог trackBy в Angular, но используется по умолчанию.

Таблица сравнения синтаксиса

| Концепция | Angular (Шаблон) | React (JSX) | | :--- | :--- | :--- | | Интерполяция | {{ value }} | {value} | | Привязка атрибута | [src]="url" | src={url} | | Слушатель событий | (click)="handler()" | onClick={handler} | | Классы стилей | [class.active]="isActive" | className={isActive ? 'active' : ''} | | Циклы | *ngFor | .map() | | Условия | *ngIf | && или ? : |

3. Виртуальный DOM (Virtual DOM)

В Angular механизм обнаружения изменений (Change Detection) опирается на Zone.js, который перехватывает асинхронные события и проверяет дерево компонентов на изменения. Это мощный, но иногда тяжеловесный механизм.

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

Процесс согласования (Reconciliation)

Когда состояние компонента меняется (например, вы вызвали setState или изменились пропсы), происходит следующее:

  • React создает новое дерево Виртуального DOM для этого компонента.
  • React сравнивает (diffing) это новое дерево с предыдущей версией Виртуального DOM.
  • React вычисляет минимально необходимый набор изменений для реального DOM.
  • React пакетно применяет эти изменения к реальному DOM.
  • !Схема работы алгоритма согласования (Reconciliation) и обновления DOM

    Почему это важно? Работа с реальным DOM — это самая медленная операция в браузере. Чтение и запись в DOM вызывают пересчет макета (reflow) и перерисовку (repaint). Виртуальный DOM позволяет минимизировать эти обращения, группируя обновления.

    4. Однонаправленный поток данных

    Angular известен своим двусторонним связыванием данных (Two-Way Data Binding), которое часто реализуется через [(ngModel)]. Это удобно для форм: изменили инпут — обновилась модель, изменили модель — обновился инпут.

    React строго придерживается однонаправленного потока данных (One-Way Data Flow).

    * Данные текут вниз: Родитель передает данные ребенку через свойства (props). * События всплывают вверх: Ребенок не может изменить пропсы. Если нужно изменить данные, ребенок вызывает функцию-колбэк, переданную родителем, и родитель меняет свое состояние.

    Пример отличия

    Представьте поле ввода имени.

    В Angular: Вы пишете <input [(ngModel)]="name">. Angular сам следит за синхронизацией.

    В React: Вы должны явно контролировать процесс:

  • Мы говорим инпуту: «Твое значение равно переменной name» (value={name}).
  • Мы говорим инпуту: «Когда пользователь печатает, вызови setName с новым значением» (onChange=...).
  • Это может показаться более многословным, но это делает поток данных предсказуемым. Вы всегда точно знаете, откуда пришли данные и что вызвало их изменение. В больших приложениях это значительно упрощает отладку.

    Заключение

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

    В следующей статье мы углубимся в сердце React-приложения — Компоненты и Пропсы, и научимся создавать переиспользуемые элементы интерфейса.

    2. Компоненты и данные: Props, State и принцип однонаправленного потока данных

    Компоненты и данные: Props, State и принцип однонаправленного потока данных

    В предыдущей статье мы разобрали, как JSX преобразуется в JavaScript и чем Виртуальный DOM отличается от инкрементального DOM в Angular. Теперь пришло время вдохнуть жизнь в наши приложения. В Angular вы привыкли мыслить классами, декораторами @Input, @Output и сервисами. В React ментальная модель проще, но строже: всё есть функция, а данные текут только в одну сторону.

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

    Анатомия компонента: Функция вместо Класса

    Исторически в React тоже были классовые компоненты, очень похожие на те, что вы пишете в Angular. Однако современный стандарт (начиная с версии 16.8) — это Функциональные компоненты.

    Если в Angular компонент — это класс с метаданными в декораторе @Component, то в React компонент — это просто JavaScript-функция, которая возвращает JSX.

    Сравнение ментальных моделей

    Angular:

    React:

    Здесь нет разделения на шаблон и класс. Функция выполняется каждый раз, когда React решает обновить интерфейс, и возвращает новую структуру UI.

    Props: Входные данные (Аналог @Input)

    В Angular для передачи данных от родителя к ребенку мы используем декоратор @Input(). В React эта концепция называется Props (сокращение от properties).

    Главное отличие: Props доступны только для чтения. Компонент не может изменить свои пропсы. Это делает компоненты чистыми функциями относительно их входных данных.

    Передача и получение Props

    Родитель передает пропсы как HTML-атрибуты:

    Дочерний компонент получает их как первый аргумент функции. Обычно мы сразу используем деструктуризацию объекта:

    > В Angular изменение @Input внутри компонента технически возможно (хоть и не рекомендуется), так как это свойство класса. В React попытка изменить пропс приведет к ошибке или непредсказуемому поведению, так как объект props заморожен.

    Особый проп: children (Аналог ng-content)

    В Angular для проекции контента (content projection) используется тег <ng-content>. В React всё, что вы помещаете между открывающим и закрывающим тегом компонента, автоматически попадает в специальный проп children.

    !Визуализация передачи данных от родителя к ребенку через Props и их неизменяемость.

    State: Внутреннее состояние (Локальные переменные)

    Пропсы приходят извне. Но как компоненту хранить собственные данные, которые могут меняться (например, счетчик кликов или текст в поле ввода)? В Angular это обычные свойства класса (this.count = 0).

    В React обычные переменные внутри функции «сбрасываются» при каждом новом вызове функции (рендере). Чтобы сохранить данные между рендерами, мы используем Хук (Hook) под названием useState.

    Синтаксис useState

    Разберем эту строку: const [count, setCount] = useState(0);

  • useState(0): Мы просим React создать ячейку памяти с начальным значением 0.
  • count: Текущее значение состояния.
  • setCount: Функция-сеттер. Только через неё можно изменить состояние.
  • Деструктуризация массива: useState всегда возвращает массив из двух элементов, которым мы даем имена.
  • Почему нельзя просто написать count = count + 1?

    В Angular механизм Change Detection (Zone.js) автоматически отслеживает изменения свойств. В React вы должны явно сообщить библиотеке, что данные изменились и нужно перерисовать компонент. Вызов функции setCount делает две вещи:

  • Обновляет значение переменной для следующего рендера.
  • Запускает процесс рендеринга (вызывает функцию компонента заново).
  • Однонаправленный поток данных (One-Way Data Flow)

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

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

    Как поднять данные наверх? (Аналог @Output)

    Если данные текут вниз, как ребенок может сообщить родителю о событии? В Angular мы используем EventEmitter и @Output. В React мы передаем функцию-колбэк через пропсы.

    Представьте, что у нас есть кнопка (ребенок), которая должна обновить счетчик в родителе.

    Родитель:

    Ребенок:

    Здесь нет магии событий. Мы просто передаем ссылку на функцию handleIncrement в проп onClick. Когда кнопка нажимается, ребенок вызывает эту функцию, которая живет в родителе. Родитель вызывает setCount, и React перерисовывает родителя (и всех его детей).

    !Схема однонаправленного потока данных: данные вниз через Props, события вверх через функции-колбэки.

    Поднятие состояния (Lifting State Up)

    Частая ситуация: у вас есть два братских компонента (Sibling A и Sibling B), и изменение в A должно повлиять на B. В Angular вы бы, возможно, использовали Сервис с BehaviorSubject.

    В React стандартный паттерн — Поднятие состояния.

  • Находим ближайшего общего родителя для A и B.
  • Перемещаем состояние (useState) в этого родителя.
  • Передаем данные в B через пропсы.
  • Передаем функцию изменения в A через пропсы.
  • Таким образом, родитель становится «источником истины» (Source of Truth) для обоих детей.

    Сводная таблица: Angular vs React

    | Концепция | Angular | React | | :--- | :--- | :--- | | Входные данные | @Input() value | props.value | | Выходные события | @Output() event = new EventEmitter() | props.onEvent() (функция-колбэк) | | Локальное состояние | Свойства класса (this.val) | useState hook | | Проекция контента | <ng-content> | props.children | | Изменение данных | Мутация (this.val = 5) | Сеттер (setVal(5)) | | Связывание | Двустороннее ([(ngModel)) | Однонаправленное (value + onChange) |

    Заключение

    Переход к React требует отказа от привычки мутировать данные напрямую. Вместо того чтобы говорить «измени переменную x на 5», вы говорите «перерисуй интерфейс с новым значением x, равным 5».

    Props и State — это два типа данных, управляющих компонентом. Props — это то, что компонент получает (как параметры функции), а State — это то, чем компонент управляет (как локальная память). Понимание того, где должно жить состояние и как оно передается через пропсы — ключ к архитектуре React-приложений.

    В следующей статье мы рассмотрим Хуки (Hooks) более подробно и узнаем, как заменить методы жизненного цикла Angular (ngOnInit, ngOnDestroy) на элегантный useEffect.

    3. Философия хуков: useState, useEffect и замена сервисов Angular функциональным подходом

    Философия хуков: useState, useEffect и замена сервисов Angular функциональным подходом

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

    В Angular для этого есть четкие инструменты: методы жизненного цикла (ngOnInit, ngOnDestroy) и Сервисы (@Injectable). В современном React (с функциональными компонентами) этих понятий в чистом виде не существует. Вместо них мы используем Хуки (Hooks).

    Хуки — это функции, которые позволяют «подцепиться» к возможностям React из функциональных компонентов. Сегодня мы сменим парадигму: перестанем думать о «жизненном цикле» и начнем думать о «синхронизации» и «композиции».

    1. Ментальная модель: От Жизненного цикла к Синхронизации

    Angular-разработчики привыкли мыслить во времени:

  • Компонент создается (constructor).
  • Компонент инициализируется (ngOnInit).
  • Компонент меняется (ngOnChanges).
  • Компонент уничтожается (ngOnDestroy).
  • В React функциональный компонент — это просто функция, которая вызывается снова и снова при каждом рендере. У функции нет «жизни», она просто выполняется.

    Чтобы выполнять побочные эффекты (side effects), такие как запросы к API или подписки, React предлагает хук useEffect.

    Синтаксис useEffect

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

  • Функция-эффект.
  • Массив зависимостей (опционально).
  • Именно массив зависимостей определяет, когда эффект будет запущен. Это позволяет одним хуком заменить ngOnInit, ngOnChanges и ngOnDestroy.

    !Сравнение управления жизненным циклом в Angular и синхронизацией в React

    2. Эмуляция жизненного цикла с помощью useEffect

    Давайте посмотрим, как переписать привычные паттерны Angular на React.

    Аналог ngOnInit (Запуск один раз)

    В Angular вы делаете первичный запрос данных в ngOnInit. В React для этого нужно передать пустой массив [] в качестве второго аргумента.

    Angular:

    React:

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

    Аналог ngOnChanges (Реакция на изменения)

    В Angular, если нужно реагировать на изменение @Input, вы используете ngOnChanges или сеттеры. В React вы просто добавляете переменную в массив зависимостей.

    Angular:

    React:

    React сам сравнивает текущее значение userId с предыдущим. Если они отличаются, эффект перезапускается.

    Аналог ngOnDestroy (Очистка)

    В Angular мы отписываемся от Observable или очищаем таймеры в ngOnDestroy. В React функция, переданная в useEffect, может вернуть другую функцию — функцию очистки.

    Angular:

    React:

    3. useState: Тонкости работы с объектами

    Мы уже касались useState, но есть важное отличие от Angular, которое часто приводит к багам.

    В Angular, изменяя свойство объекта, вы мутируете его:

    В React состояние неизменяемо (immutable). Хук useState не сливает объекты автоматически (как это делал setState в классовых компонентах React или как вы привыкли в Angular).

    Всегда используйте оператор spread (...) для копирования предыдущих полей объекта.

    4. Замена Сервисов: Пользовательские хуки (Custom Hooks)

    В Angular логика выносится в Сервисы (@Injectable). Сервисы — это классы, которые предоставляют методы и хранят состояние. Они внедряются через Dependency Injection.

    В React нет встроенного DI-контейнера в том виде, как в Angular. Вместо сервисов мы используем Пользовательские хуки (Custom Hooks).

    Пользовательский хук — это просто JavaScript-функция, имя которой начинается с use, и которая может вызывать другие хуки.

    Пример: Логика загрузки данных

    Представьте, что у вас есть сервис UserService в Angular.

    Angular (Service):

    В React мы создадим хук useUsers.

    React (Custom Hook):

    Использование в компоненте

    Теперь любой компонент может использовать эту логику одной строкой:

    Это мощнейший паттерн. Хуки позволяют инкапсулировать логику состояния и побочных эффектов, делая компоненты чистыми и простыми. В отличие от сервисов Angular, которые часто являются синглтонами, вызов useUsers() в двух разных компонентах создаст два независимых состояния (если только вы специально не используете Context API или внешние стейт-менеджеры).

    !Вынесение бизнес-логики из компонента в пользовательский хук

    5. Правила Хуков

    У хуков есть два строгих правила, которые контролируются линтером (eslint-plugin-react-hooks):

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

    Хорошо:

    Заключение

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

    * useState заменяет поля класса. * useEffect заменяет методы жизненного цикла (ngOnInit, ngOnChanges, ngOnDestroy). * Пользовательские хуки (useSomething) заменяет сервисы для переиспользования логики.

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

    4. Работа с формами, списками и асинхронными запросами к API

    Работа с формами, списками и асинхронными запросами к API

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

    В Angular у вас есть мощные инструменты «из коробки»: FormsModule для форм, директива *ngFor для списков и HttpClient для общения с сервером. React, будучи библиотекой, а не фреймворком, предлагает более низкоуровневый, но гибкий подход. Здесь нет магии двустороннего связывания или встроенных HTTP-клиентов. Есть только JavaScript и состояние.

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

    1. Формы в React: Контролируемые компоненты

    В Angular мы привыкли к двум подходам: Template-driven forms (с использованием [(ngModel)]) и Reactive Forms. В React стандарт де-факто — это Контролируемые компоненты (Controlled Components).

    Что такое контролируемый компонент?

    В HTML элементы формы (такие как <input>, <textarea>, <select>) обычно сами хранят свое состояние. В React мы хотим, чтобы единственным источником истины было состояние компонента (state).

    Мы делаем две вещи:

  • Привязываем атрибут value инпута к переменной состояния.
  • Вешаем обработчик onChange, который обновляет состояние при каждом вводе пользователя.
  • !Круговорот данных в контролируемом компоненте: Input вызывает изменение State, а State диктует значение Input

    Пример простого инпута

    В Angular:

    В React:

    Это кажется более многословным, чем [(ngModel)], но это дает полный контроль. Вы можете форматировать ввод на лету (например, превращать все в верхний регистр) или валидировать его до обновления состояния.

    Обработка отправки формы

    В Angular мы используем (ngSubmit). В React — стандартное событие onSubmit на теге <form>. Важно помнить: в SPA мы должны предотвратить стандартное поведение браузера (перезагрузку страницы) с помощью event.preventDefault().

    Работа с несколькими полями

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

    > Обратите внимание на атрибут name у инпутов. Он позволяет нам определить, какое именно поле изменилось, и использовать вычисляемые свойства объекта ([name]: value).

    2. Списки и ключи: Замена *ngFor

    В Angular для отображения массивов используется структурная директива *ngFor. В React мы используем нативные возможности JavaScript, а именно метод массива .map().

    Рендеринг списка

    Допустим, у нас есть массив пользователей.

    Angular:

    React:

    Зачем нужен атрибут key?

    Вы заметили атрибут key={user.id}. Это критически важный элемент. Он является прямым аналогом функции trackBy в Angular.

    React использует ключи, чтобы понять, какие элементы списка были изменены, добавлены или удалены. Это помогает алгоритму согласования (Reconciliation) работать эффективно.

    Правила выбора ключа:

  • Уникальность: Ключ должен быть уникальным среди соседей (внутри одного массива).
  • Стабильность: Не используйте случайные числа (Math.random()) или индексы массива (index из map), если порядок элементов может меняться. Использование индекса в качестве ключа может привести к ошибкам состояния компонентов и проблемам с производительностью при сортировке или фильтрации.
  • !Визуализация работы алгоритма Reconciliation с ключами и без

    3. Асинхронные запросы: Жизнь без HttpClient

    Angular поставляется с мощным HttpClient, основанным на RxJS (Observable). В React нет встроенного HTTP-клиента. Вы вольны использовать: * Встроенный в браузер fetch API (на основе Promise). * Сторонние библиотеки, например axios. Библиотеки для управления серверным состоянием (React Query, SWR) — о них мы поговорим в продвинутых курсах*.

    Для начала разберем классический подход с fetch и хуком useEffect.

    Паттерн загрузки данных

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

  • Загрузка (Loading).
  • Успех (Data).
  • Ошибка (Error).
  • Сравнение с Angular

    В Angular мы бы подписались на Observable в ngOnInit:

    В React мы используем промисы и async/await. Если вы скучаете по RxJS, вы можете использовать его и в React, но это не является стандартом для простых задач.

    4. Практический пример: Поиск по списку

    Давайте объединим формы, списки и эффекты. Сделаем компонент, который фильтрует список пользователей по введенному тексту.

    Обратите внимание: нам не нужно создавать отдельное состояние filteredUsers и обновлять его в useEffect. Мы просто вычисляем переменную filteredUsers на основе users и query при каждом рендере. React работает достаточно быстро, чтобы делать такие операции на лету для небольших списков.

    Заключение

    Мы рассмотрели три кита интерактивного интерфейса:

  • Формы: Используем паттерн «Контролируемый компонент», связывая value и onChange.
  • Списки: Используем метод .map() и обязательно задаем уникальный key.
  • API: Используем useEffect для выполнения побочных эффектов (запросов) и useState для хранения результатов.
  • Вам больше не нужны FormsModule или HttpClientModule. Вы используете чистый JavaScript и хуки React. Это дает больше свободы, но требует больше дисциплины в управлении состоянием.

    В следующей статье мы поговорим о навигации и маршрутизации, рассмотрев стандартную библиотеку React Router.

    5. Экосистема React: Настройка маршрутизации и управление глобальным состоянием через Context API

    Экосистема React: Настройка маршрутизации и управление глобальным состоянием через Context API

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

    В мире Angular у вас есть мощный встроенный модуль RouterModule и система Dependency Injection (DI) для обмена данными между несвязанными компонентами через Сервисы. В React, следуя философии «это просто библиотека», эти вещи вынесены за скобки ядра.

    В этой статье мы превратим набор разрозненных компонентов в полноценное SPA (Single Page Application). Мы подключим самую популярную библиотеку для маршрутизации React Router и научимся бороться с «прокидыванием пропсов» (prop drilling) с помощью встроенного инструмента Context API.

    1. Маршрутизация: React Router

    В отличие от Angular, где роутер является частью фреймворка, в React вам нужно установить его отдельно. Стандартом де-факто является библиотека react-router-dom.

    Установка и базовая настройка

    Чтобы начать, нужно обернуть все приложение в компонент BrowserRouter. Это аналог <router-outlet> и конфигурации модулей в Angular, но работающий через композицию компонентов.

    Теперь внутри App мы можем определять маршруты. В Angular вы пишете массив объектов с путями. В React вы пишете JSX-разметку.

    !Визуализация сопоставления URL и компонентов в React Router

    Навигация и параметры

    Переход по ссылкам: Вместо тега <a>, который перезагружает страницу, мы используем компонент <Link>. Это прямой аналог директивы routerLink в Angular.

    Программная навигация: В Angular вы инжектируете Router и вызываете this.router.navigate(['/path']). В React мы используем хук useNavigate.

    Получение параметров URL: В Angular мы используем ActivatedRoute. В React для этого есть хук useParams.

    2. Проблема Prop Drilling

    Представьте, что у вас есть данные о текущем пользователе в корневом компоненте App. Эти данные нужны компоненту Avatar в шапке, компоненту ProfileSettings глубоко в настройках и компоненту Comment в ленте.

    В React данные передаются только сверху вниз. Чтобы доставить данные на 5 уровней вниз, вам придется передавать их через все промежуточные компоненты, даже если они им не нужны. Это называется Prop Drilling (сверление пропсов).

    В Angular эта проблема решается через Сервисы (Singleton), которые можно заинжектить в любом месте. В React для этого существует Context API.

    !Иллюстрация проблемы Prop Drilling и её решения с помощью Context API

    3. Context API: Глобальное состояние

    Context API позволяет передавать данные через дерево компонентов без необходимости передавать пропсы на промежуточных уровнях. Это встроенный механизм React для Dependency Injection.

    Работа с контекстом состоит из трех шагов:

  • Создание контекста (createContext).
  • Предоставление данных (Context.Provider).
  • Потребление данных (useContext).
  • Шаг 1: Создание контекста

    Создадим отдельный файл для контекста аутентификации.

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

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

    Шаг 3: useContext (Потребитель)

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

    4. Паттерн «Провайдер как Сервис»

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

    Это лучшая практика, которая позволяет инкапсулировать логику работы с состоянием (например, авторизацию) в одном месте, очищая App.js.

    Теперь App.js становится чище:

    А любой компонент может вызвать метод login:

    5. Когда использовать Context, а когда Redux?

    Angular-разработчики часто знакомы с NgRx (реализация Redux для Angular). В React экосистеме есть Redux Toolkit, Zustand, MobX и другие менеджеры состояния.

    Context API — это не менеджер состояния, это транспорт. Он идеально подходит для: * Темы оформления (светлая/темная). * Данных текущего пользователя (Auth). * Языка интерфейса (i18n). * Данных, которые редко меняются.

    Если у вас сложные данные, частые обновления и сложная бизнес-логика, Context может вызвать проблемы с производительностью (лишние ререндеры). В таких случаях стоит смотреть в сторону Redux Toolkit или Zustand. Но для большинства приложений среднего размера связки useState + Context API более чем достаточно.

    Заключение курса

    Мы прошли путь от базового синтаксиса JSX до создания полноценной архитектуры приложения.

  • Компоненты заменили нам контроллеры и шаблоны.
  • Props заменили @Input.
  • useState заменил свойства класса.
  • useEffect заменил методы жизненного цикла.
  • React Router дал нам навигацию.
  • Context API заменил простые сервисы.
  • React дает вам свободу выбора инструментов. Здесь нет «единственно верного способа Angular», но есть устоявшиеся паттерны и огромное сообщество. Главный совет при переходе: перестаньте искать прямые аналоги инструментов Angular. Вместо этого сфокусируйтесь на философии React — композиция функций и однонаправленный поток данных.

    Добро пожаловать в React!