React 19 приносит множество долгожданных нововведений, которые призваны упростить работу с асинхронными данными, оптимизировать производительность приложений и избавить разработчиков от рутинного кода. Фронтенд-инструктор платформы Scrimba Боб Зиролл в своем практическом мини-курсе подробно разбирает ключевые изменения новой мажорной версии, находящейся в статусе Release Candidate. В центре внимания — автоматический компилятор, концепция Actions, новые специализированные хуки и уникальный API use.
⏳ Эволюция управления состоянием: от переходов к операциям 2:25
Для понимания ключевых новшеств React 19 необходимо разобраться в концепции переходов (Transitions), появившейся еще в React 18. Боб Зиролл демонстрирует проблему на примере переключения вкладок интерфейса: при переходе на вкладку «Продукты» компонент генерирует список из 1500 элементов с искусственной задержкой отрисовки в 1 миллисекунду на элемент с помощью библиотеки Faker JS, что суммарно дает задержку в 1,5 секунды. Если пользователь кликает на медленную вкладку, а затем сразу выбирает другую, стандартный механизм React выстраивает обновления в очередь и блокирует интерфейс до завершения тяжелого рендеринга.
Использование хука useTransition решает эту проблему, указывая React, что определенные изменения состояния имеют низкий приоритет и могут быть прерваны.
Хук возвращает массив из двух элементов:
isPending— булево значение, сигнализирующее о выполнении перехода в фоне.startTransition— функция-обертка для низкоприоритетных обновлений состояния.
Благодаря встроенному флагу isPending разработчикам больше не требуется вручную создавать громоздкий бойлерплейт с useState для отслеживания состояния загрузки. Интерфейс становится отзывчивым, сбрасывая тяжелые фоновые задачи, если пользователь передумал и кликнул на другую вкладку.
🛠️ Автоматическая оптимизация с React Compiler 11:25
Одним из главных технологических прорывов версии React 19 стал встроенный компилятор, ранее известный под кодовым названием React Forget. Этот инструмент анализирует исходный код на этапе сборки и автоматически внедряет оптимизации производительности там, где это необходимо.
По словам Боба Зиролла, с полноценным внедрением компилятора у разработчиков отпадет необходимость в ручном управлении мемоизацией. В частности, можно будет практически полностью отказаться от использования следующих инструментов:
react.memouseMemouseCallback
На момент записи курса документация компилятора находилась в стадии бета-тестирования, однако проект уже полностью открыт для сообщества (open-source). Компилятор берет на себя всю рутину по вычислению потенциальных узких мест производительности программы.
📦 Концепция Actions и нативная работа с формами 13:08
Важным архитектурным изменением стало появление концепции Actions, ориентированной на обработку мутаций данных. В официальной документации React под «действиями» (Actions) понимаются функции, использующие асинхронные переходы. Боб Зиролл отмечает, что это определение может показаться запутанным, но на практике оно сводится к нативному способу изменения данных в экосистеме React.
Первое и наиболее очевидное применение Actions — передача функции напрямую в проп action стандартного HTML-элемента <form>. По мнению спикера, в традиционном React управление формами всегда считалось одной из самых проблемных зон. Разработчикам приходилось выполнять много рутинных действий:
- Контролировать каждый ввод через связку параметров
valueиonChangeдля обновления локального состояния на каждый символ. - Вручную вызывать
event.preventDefault()в обработчикеonSubmit, чтобы избежать перезагрузки страницы браузером. - Императивно обрабатывать состояния отправки, сброса полей и ошибок.
React 19 предлагает кардинально иной подход. Функция, переданная в проп action, автоматически принимает нативный объект FormData. Это позволяет извлекать данные по атрибуту name с помощью метода formData.get('name'), избавляя от необходимости синхронизировать ввод с состоянием компонента и вручную отменять стандартное поведение отправки формы.
🔄 Управление асинхронным состоянием с помощью useActionState 23:32
Для обработки комплексных сценариев отправки форм, включающих отслеживание ошибок и стадий загрузки, в React 19 представлен специализированный хук useActionState. Этот инструмент автоматизирует управление жизненным циклом асинхронной операции.
Синтаксис хука useActionState возвращает кортеж из трех элементов:
- Текущее состояние (
state). - Обернутая функция действия для привязки к форме (
formAction). - Флаг активности процесса (
isPending).
Принцип работы передаваемой функции во многом напоминает редюсеры в Redux или стандартный хук useReducer. Функция принимает два аргумента: предыдущее состояние компонента (previousState) и объект formData. Результат выполнения функции автоматически становится новым состоянием.
Для полноценного отслеживания ошибок Боб Зиролл рекомендует переводить состояние с примитивного уровня (строки) на уровень объектов. Это позволяет хранить одновременно и полезные данные, и сообщения об ошибках. Спикер подчеркивает важность явного копирования или сохранения свойств предыдущего состояния (например, через деструктуризацию), чтобы избежать перезаписи и потери актуальных данных при возникновении ошибок.
🚀 Мгновенный отклик интерфейса с useOptimistic 41:59
Статистически подавляющее большинство запросов к базам данных завершаются успешно, поэтому долгое ожидание ответа сервера ухудшает пользовательский опыт. Хук useOptimistic позволяет мгновенно обновить UI, предполагая успешный исход операции, и автоматически откатить изменения в случае сбоя.
Боб Зиролл приводит аналогию с современными социальными сетями, например, Twitter: когда пользователь нажимает кнопку «лайк», сердечко окрашивается моментально, а фактический запрос выполняется в фоновом режиме.
Реализация оптимистичного обновления требует интеграции хука в цепочку вызовов Actions:
- Инициализируется состояние:
const [optimisticName, setOptimisticName] = useOptimistic(state.name);. - Внутри асинхронной функции, до выполнения сетевого запроса, вызывается
setOptimisticName(formData.get('name')). - В интерфейсе пользователю выводится переменная
optimisticName.
Если фоновый запрос падает с ошибкой, React самостоятельно возвращает значение к исходному state.name и отображает ошибку. По мнению спикера, такой подход делает приложение субъективно гораздо более «отзывчивым» и избавляет от необходимости показывать навязчивые индикаторы загрузки.
🔌 Инкапсуляция контекста формы через useFormStatus 47:31
При проектировании библиотек компонентов или глубоко вложенных элементов форм возникает проблема передачи состояния загрузки (prop drilling). Создание собственного React-контекста для этой задачи усложняет архитектуру. Решением становится новый хук useFormStatus.
Этот хук работает как автоматический потребитель контекста (context consumer) ближайшей родительской формы. Важной особенностью является то, что useFormStatus импортируется из пакета react-dom, а не из ядра react. Боб Зиролл объясняет это тем, что превращение HTML-формы в провайдер контекста завязано непосредственно на работу с DOM-деревом.
Вызов хука возвращает объект со следующими свойствами:
pending— статус отправки формы.data— экземплярFormData, отправляемый в данный момент.method— HTTP-метод формы (например, GET или POST).action— ссылка на саму функцию действия.
Это позволяет легко создавать кастомные кнопки отправки, которые самостоятельно меняют свой текст на «Отправка...» или блокируются, не требуя передачи пропсов сверху.
🎯 Прямая передача рефов (Refs) как обычных пропсов 52:12
Рефы в React используются для сохранения информации между рендерами без инициации повторного рендеринга, чаще всего — для хранения ссылок на нативные DOM-узлы (например, для программной установки фокуса на инпуте).
В React 18 и более ранних версиях прямая передача рефа в дочерний кастомный компонент была невозможна. Разработчикам приходилось использовать специальную функцию-обертку forwardRef, которая передавала реф вторым параметром функции компонента. Команда React позиционировала это как временное решение.
В React 19 API библиотеки было оптимизировано: теперь ref является обычным пропсом наряду с children и другими параметрами. Больше нет необходимости использовать forwardRef, что существенно упрощает код кастомных библиотек компонентов.
🔮 Универсальный API use для асинхронных ресурсов 55:05
Одним из самых обсуждаемых и необычных нововведений стал API под названием use. Боб Зиролл обращает внимание на критически важный нюанс: это именно API, а не хук, поэтому он не подчиняется строгим правилам хуков. Его можно вызывать условно — внутри блоков if или циклов.
Инструмент предназначен для чтения асинхронных ресурсов (промисов) или контекста прямо во время рендеринга. До появления use загрузка данных в чистом React требовала использования хука useEffect при монтировании компонента и сохранения результата в локальное состояние useState.
С помощью use код можно писать в квази-синхронном стиле: const data = use(fetchPromise). При вызове этой инструкции компонент автоматически «приостанавливает» свой рендеринг (suspends). Для корректной работы приложение обязательно должно быть обернуто в компонент <Suspense> с указанием резервного интерфейса (fallback), который будет показываться во время ожидания данных.
Тем не менее, спикер предупреждает о текущем жестком ограничении: создание промисов (например, вызов fetch()) непосредственно внутри тела клиентского компонента на каждом рендере приведет к бесконечным запросам и вызовет предупреждение об «некэшированном промисе». На текущем этапе для использования use необходимы внешние библиотеки или фреймворки, поддерживающие кэширование промисов, хотя в будущем команда React планирует добавить нативный механизм кэширования в рендере.
📑 Автоматический подъем метаданных документа 1:04:10
Завершая обзор, Боб Зиролл выделил встроенную поддержку метаданных документа. Традиционно в React-приложениях компоненты рендерят контент внутрь корневого элемента (обычно <div id="root">), расположенного в теге <body>, из-за чего прямого доступа к тегу <head> нет. Для динамического изменения заголовков страниц в целях SEO приходилось подключать сторонние библиотеки, такие как react-helmet.
В React 19 разработчики могут объявлять теги <title>, <meta> и <link> в любом месте компонентного дерева. React автоматически перенесет (hoist) эти элементы в заголовок документа <head>. Это существенно упрощает базовую SEO-оптимизацию веб-страниц без привлечения лишних внешних зависимостей.