Каковы основные отличия React 18 от React 19?
React 19 стабилизирует Server Components и Server Actions, вводит хук use(promise|context), Actions-стек (useActionState, useFormStatus, useOptimistic), ref как обычный prop без forwardRef, нативные метаданные документа из компонентов и React Compiler. Concurrent-модель React 18 остаётся фундаментом; 19 её достраивает.
Концептуальный сдвиг
React 18 был релизом concurrent-рендеринга: Fiber-приоритеты, useTransition, useDeferredValue, автоматический батчинг, потоковый SSR. React 19 не меняет этот фундамент — он завершает разрозненные эксперименты: серверные компоненты и Actions выходят в стабильную поставку, появляется хук use, упрощается работа с ref и формами, поставляется React Compiler. Это релиз «сшивающий» async-UI-модель.
Ключевые изменения React 19
use(promise | context)— стабильный хук для чтения промиса (с Suspense-приостановкой) и контекста (можно вызывать условно, в отличие отuseContext).- Actions — единый стек для асинхронных мутаций:
<form action={asyncFn}>,useActionState,useFormStatus,useOptimistic. Заменяет ручную связкуuseReducer+useTransition+ флаги pending/error. - Server Components и Server Actions — стабильные. В React 18 они были canary-экспериментом, активно менялись и требовали поддержки конкретного фреймворка.
- ref как обычный prop —
forwardRefбольше не нужен для функциональных компонентов. Старый API остаётся, но помечается deprecated. - Document metadata —
<title>,<meta>,<link rel="stylesheet">можно рендерить внутри любого компонента; React поднимает их в<head>и дедуплицирует. - Resource Preloading API —
react-domэкспортируетpreinit,preload,prefetchDNS,preconnect; стили приоритизируются черезprecedence. - React Compiler — отдельный пакет, AOT-оптимизатор, автоматизирует мемоизацию без ручного
useMemo/useCallback. - Улучшенный hydration error reporting — вместо общего «html mismatch» теперь конкретный diff клиентского и серверного дерева.
useDeferredValue(value, initialValue)— новый второй аргумент задаёт значение до первого апдейта.- Asset loading coordination — React 19 ожидает загрузки стилей и шрифтов перед commit, устраняя FOUC.
Пример: Actions + ref prop
// React 18: forwardRef обязателен для передачи ref
import { forwardRef, useReducer, useTransition } from "react";
const Input18 = forwardRef<HTMLInputElement, { label: string }>(
function Input({ label }, ref) {
return <input ref={ref} aria-label={label} />;
}
);
// Мутация вручную
function Form18() {
const [pending, startTransition] = useTransition();
const [error, setError] = useReducer((_: unknown, e: string) => e, "");
function handleSubmit(e: React.FormEvent) {
e.preventDefault();
startTransition(async () => {
try {
await save();
} catch (err) {
setError(String(err));
}
});
}
return <form onSubmit={handleSubmit}>{pending ? "Saving…" : "Save"}{error}</form>;
}
// ─────────────────────────────────────────────
// React 19: ref — обычный prop, Actions упрощают мутации
import { useActionState } from "react";
function Input19({ label, ref }: { label: string; ref?: React.Ref<HTMLInputElement> }) {
return <input ref={ref} aria-label={label} />;
}
async function saveAction(_prev: { error: string }, data: FormData) {
try {
await save(data.get("name") as string);
return { error: "" };
} catch (err) {
return { error: String(err) };
}
}
function Form19() {
const [state, action, isPending] = useActionState(saveAction, { error: "" });
return (
<form action={action}>
<title>Profile</title>{/* React поднимет в <head> */}
<Input19 label="Name" />
<button disabled={isPending}>{isPending ? "Saving…" : "Save"}</button>
{state.error && <p role="alert">{state.error}</p>}
</form>
);
}
Что НЕ изменилось
Из React 18 остаются: автобатчинг, useTransition, useDeferredValue, useSyncExternalStore, useId, потоковый SSR, createRoot/hydrateRoot. React 19 — эволюция, не переписывание.
Подводные камни
- Удалены устаревшие API:
propTypes/defaultPropsу функциональных компонентов, строковые refs, часть UMD-сборок — при апгрейде нужен явный аудит. - Server Components требуют фреймворка: в чистом Vite/CRA SPA они недоступны — только Next.js App Router, Waku и аналоги умеют их запускать.
- React Compiler не серебряная пуля: на коде с нарушением правил хуков или мутацией пропсов он просто отказывается оптимизировать модуль, не ломая его. Чистить код всё равно придётся.
- Document metadata конфликтует с react-helmet: нативный подъём тегов и сторонние менеджеры метаданных несовместимы — нужно выбрать одно.
- Ужесточён стандарт гидратации: часть несоответствий, которые React 18 молча исправлял, React 19 теперь бросает как ошибки с подробным diff — старые баги «всплывут».
- useOptimistic требует Actions: вне контекста
startTransitionилиaction-prop оптимистичные апдейты не откатятся автоматически при ошибке. - Asset loading coordination меняет порядок commit: если страница зависит от внешних шрифтов и стилей, добавление
precedenceможет изменить момент первой отрисовки — проверяйте LCP. - Deprecation forwardRef не означает мгновенного удаления: API остаётся рабочим в 19, но линтер начнёт предупреждать — план удаления на будущий major.
Common mistakes
- Считать
useсинтаксическим сахаром дляawait. - Удалять
forwardRefиuseMemoоптом без проверки тестами. - Смешивать
react-helmetи новые document metadata в одном дереве.
What the interviewer is testing
- Знает ли стабилизованные в 19 API.
- Понимает ли связь Actions/Compiler/RSC.
- Может ли назвать осторожные шаги миграции.