React 19 стал одним из самых ожидаемых обновлений для фронтенд-разработчиков за последние несколько лет. Эта версия не только добавляет новые возможности, но и устраняет значительную часть повторяющегося кода, который разработчики писали годами. Управление состоянием форм, асинхронные операции, чтение данных и даже управление метаданными страницы теперь реализуются гораздо естественнее и с меньшим объёмом кода. В этой статье мы рассмотрим самые важные стабильные функции React 19 на реальных практических примерах и ответим на вопрос, стоит ли обновлять ваш проект.
Actions: новый способ управления формами и асинхронным состоянием
Одним из главных изменений в React 19 стала концепция Actions. Раньше при отправке формы приходилось вручную управлять состоянием загрузки, ошибками и оптимистичными обновлениями. Для этого писалось несколько вызовов useState, блоки try-catch и ручные изменения состояния. React 19 упрощает этот процесс с помощью хука useActionState, который напрямую связывает асинхронную функцию с формой.
import { useActionState } from "react";
function UpdateName() {
const [error, submitAction, isPending] = useActionState(
async (previousState, formData) => {
const name = formData.get("name");
const result = await updateName(name);
if (result.error) return result.error;
redirect("/profile");
return null;
},
null
);
return (
<form action={submitAction}>
<input name="name" />
<button disabled={isPending}>Сохранить</button>
{error && <p>{error}</p>}
</form>
);
}
Преимущество этого подхода в том, что состояние isPending управляется автоматически, и вам не нужно устанавливать его вручную. Во время отправки формы кнопка блокируется сама, а после получения ответа снова становится активной. В старом подходе эту логику приходилось переписывать в каждой форме, теперь же React берёт её на себя. Это особенно заметно снижает объём кода в приложениях с большим количеством форм.
useOptimistic: оптимистичные обновления стали проще
В современных интерфейсах пользователь ожидает увидеть результат действия мгновенно, даже если ответ сервера ещё не пришёл. Это называется оптимистичным обновлением, и раньше его реализация была довольно сложной. В React 19 хук useOptimistic сильно упрощает эту задачу и автоматически откатывает состояние при ошибке.
import { useOptimistic } from "react";
function Thread({ messages, sendMessage }) {
const [optimisticMessages, addOptimistic] = useOptimistic(
messages,
(state, newMessage) => [...state, { text: newMessage, sending: true }]
);
async function formAction(formData) {
const text = formData.get("message");
addOptimistic(text);
await sendMessage(text);
}
return (
<form action={formAction}>
{optimisticMessages.map((m, i) => (
<div key={i}>{m.text} {m.sending && "(отправка...)"}</div>
))}
<input name="message" />
</form>
);
}
Здесь сообщение появляется на экране сразу, не дожидаясь доставки на сервер, и отображается с пометкой «отправка». Если на сервере возникает ошибка, React автоматически отменяет оптимистичное состояние и возвращает исходные данные. Такой опыт делает интерфейс гораздо более отзывчивым и живым в местах, требующих быстрой реакции, например в чатах, комментариях и лайках.
Хук use(): гибкий способ чтения данных и контекста
React 19 представляет новый API под названием use. В отличие от обычного хука, его можно вызывать условно, например внутри блока if. use принимает Promise и может читать его результат вместе с Suspense, либо использоваться вместо useContext для получения значения контекста.
import { use, Suspense } from "react";
function Comments({ commentsPromise }) {
const comments = use(commentsPromise);
return comments.map((c) => <p key={c.id}>{c.text}</p>);
}
function Page({ commentsPromise }) {
return (
<Suspense fallback={<p>Загрузка...</p>}>
<Comments commentsPromise={commentsPromise} />
</Suspense>
);
}
В старом подходе для загрузки данных приходилось вызывать fetch внутри useEffect и сохранять результат в useState, что приводило к лишним рендерам и сложному управлению состоянием. С use же Promise читается напрямую, а Suspense автоматически управляет состоянием загрузки. Кроме того, использование use вместо useContext позволяет читать контекст условно, что раньше было невозможно.
ref как проп: forwardRef больше не нужен
Долгие годы для передачи ref в другой компонент приходилось оборачивать его в forwardRef. Это создавало дополнительный шаблонный код и иногда приводило к путанице. В React 19 функциональные компоненты могут принимать ref как обычный проп, что значительно очищает код.
function MyInput({ placeholder, ref }) {
return <input placeholder={placeholder} ref={ref} />;
}
// Использование:
function Form() {
const inputRef = useRef(null);
return <MyInput placeholder="Имя" ref={inputRef} />;
}
Теперь вы можете полностью отказаться от forwardRef и объявлять ref в ряду других пропов. Это изменение особенно полезно в крупных библиотеках компонентов, поскольку избавляет от лишней обёртки каждый переиспользуемый компонент. Старый код с forwardRef продолжает работать, но в новых проектах рекомендуется использовать подход с прямым пропом, а в будущем старый API будет постепенно выводиться из употребления.
Метаданные документа: управление title и meta-тегами из компонента
Для SEO важны заголовок страницы и meta-теги, но раньше для управления ими требовались внешние библиотеки вроде react-helmet. В React 19 вы можете писать теги <title>, <meta> и <link> прямо внутри компонента, и React автоматически поднимает их в раздел <head> документа.
function BlogPost({ post }) {
return (
<article>
<title>{post.title} — блог sayt.uz</title>
<meta name="description" content={post.excerpt} />
<meta property="og:title" content={post.title} />
<h1>{post.title}</h1>
<p>{post.content}</p>
</article>
);
}
Этот подход позволяет хранить метаданные рядом с компонентом, к которому они относятся, что делает код логичным и понятным. При использовании вместе с Server Components эта функция добавляет правильные meta-теги в HTML, отрендеренный на сервере, что крайне важно для поисковых систем. Теперь во многих случаях внешняя библиотека больше не нужна, и управление метаданными становится естественной частью React.
Server Components и улучшенная гидрация
React 19 представляет Server Components как стабильную функцию. Эти компоненты рендерятся на сервере, и клиенту отправляется готовый HTML, что ускоряет первоначальную загрузку и уменьшает объём JavaScript. Server Components могут обращаться напрямую к базе данных и отправлять клиенту только необходимые данные, что снижает нагрузку на сеть.
Кроме того, React 19 значительно улучшил процесс гидрации. Гидрация — это процесс добавления интерактивности к HTML, отрендеренному на сервере, и раньше при ошибках она могла сломать всю страницу. В новой версии ошибки гидрации сообщаются гораздо точнее, а React способен автоматически восстанавливать некоторые несоответствия. Это повышает стабильность приложения, особенно когда контент на стороне сервера и клиента немного различается.
Стоит ли обновляться и как мигрировать
Переход на React 19 для большинства проектов проходит относительно гладко, поскольку команда сделала многие изменения обратно совместимыми. Перед началом миграции рекомендуется сначала обновиться до версии React 18.3, так как она выдаёт предупреждения об устаревших функциях, которые удаляются в 19. Затем с помощью инструмента react-codemod можно применить автоматические преобразования, что сокращает объём ручной работы.
Если ваш проект активно работает с формами, асинхронными операциями и SEO, переход на React 19 принесёт значительную пользу и уменьшит объём кода. Для небольших и стабильно работающих проектов спешить не обязательно, но новые функции в долгосрочной перспективе делают разработку гораздо удобнее. В целом React 19 стал серьёзным шагом, упрощающим современную фронтенд-разработку и улучшающим опыт разработчиков, поэтому новые проекты разумно начинать именно с него.