FFlauron
React + Next.js Pro: сучасний фронтенд
Безкоштовний урок-прев'ю

React 19: огляд нового — Actions, useOptimistic, use(), ref у props

React 19 (грудень 2024) — найбільший реліз з 16.8 (hooks). Принципово нові концепції: Actions, useOptimistic, use() як promise reader, ref як prop. Розбираємо що змінилось і як це впливає на код у 2026.

Що нового в React 19

Фіча Що дає
Actions Native async-функції у формах + автоматичні pending/error states
useOptimistic Тимчасовий optimistic state доки чекаємо server
useActionState Заміна useFormState для Server Actions
use() Читання promise / context прямо у render
ref як prop Більше не потрібен forwardRef для простих компонентів
Document metadata <title>, <meta> прямо у компонентах
Stylesheet precedence Сортування CSS під капотом
Async transitions useTransition тепер працює з async функціями

Actions — нова модель async-роботи

До 19: писав useState(loading), useState(error), try/catch у handler. Багато boilerplate.

Тепер:

function UpdateNameForm() {
  const [error, submitAction, isPending] = useActionState(
    async (previousState, formData) => {
      const name = formData.get("name");
      const result = await updateName(name);
      if (result.error) return result.error;
      return null;
    },
    null,
  );

  return (
    <form action={submitAction}>
      <input name="name" />
      <button disabled={isPending}>
        {isPending ? "Зберігаю…" : "Зберегти"}
      </button>
      {error && <p>{error}</p>}
    </form>
  );
}

Pending і error tracking — автоматично. Boilerplate зник.

useOptimistic — миттєвий feedback

UI оновлюється до відповіді сервера. Якщо сервер впав — rollback.

function MessageList({ messages, sendMessage }) {
  const [optimisticMessages, addOptimistic] = useOptimistic(
    messages,
    (state, newMessage) => [...state, { text: newMessage, pending: true }]
  );

  async function action(formData) {
    addOptimistic(formData.get("text"));
    await sendMessage(formData.get("text"));
  }

  return (
    <>
      {optimisticMessages.map((m, i) => (
        <p key={i} style={{ opacity: m.pending ? 0.5 : 1 }}>{m.text}</p>
      ))}
      <form action={action}>...</form>
    </>
  );
}

UX як у Twitter — повідомлення з'являється миттєво.

use() — читання promise у render

До 19: const data = await fetch(...) лише у Server Component. У клієнті — useEffect + useState.

Тепер у Client Component:

function UserProfile({ userPromise }) {
  const user = use(userPromise); // suspend поки promise не resolved
  return <h1>{user.name}</h1>;
}

// Wrapper:
<Suspense fallback={<Spinner />}>
  <UserProfile userPromise={fetchUser(id)} />
</Suspense>

use() працює з:

  • Promise (suspend поки не resolve)
  • Context (заміна useContext, можна викликати умовно)

ref як prop — без forwardRef

До 19:

const Input = forwardRef<HTMLInputElement, Props>((props, ref) => (
  <input ref={ref} {...props} />
));

Після 19:

function Input({ ref, ...props }: Props & { ref: Ref<HTMLInputElement> }) {
  return <input ref={ref} {...props} />;
}

forwardRef — більше не потрібен. Чистіше і typed краще.

Document metadata — без next/head

function ProductPage({ product }) {
  return (
    <>
      <title>{product.name}</title>
      <meta name="description" content={product.description} />
      <h1>{product.name}</h1>
    </>
  );
}

React автоматично переносить ці елементи у <head>. Працює і на сервері, і на клієнті.

⚠ В Next.js — використовуй metadata export або generateMetadata для SEO. React 19 docu metadata — fallback для не-Next-додатків.

Compiler — auto-memoization (Preview)

React Compiler (поки RC у 2025-2026) автоматично робить memo/useMemo/useCallback. Більше не потрібно вручну:

// До compiler'а:
const expensive = useMemo(() => compute(a, b), [a, b]);
const handleClick = useCallback(() => doX(c), [c]);

// З compiler'ом:
const expensive = compute(a, b);
const handleClick = () => doX(c);
// Compiler сам перетворює це у memoized версію

У 2026 поступово стає default. Перевір react-compiler ESLint plugin.

Що НЕ змінилось / часті помилки

  • useState працює як завжди
  • useEffect — без змін, не використовуй його для data fetching (use() + Suspense)
  • Class components — все ще працюють, але legacy
  • React 18 patterns — сумісні

Setup нового проєкту з React 19

npx create-next-app@latest my-app --typescript --app --tailwind
cd my-app
npm install
npm run dev

Next.js 15+ використовує React 19 за умовчанням.

Тест: перевір себе нижче

Інтерактивні задачі під уроком — single-choice, multi-choice, code. Проходь, отримуй ✓ на кожний урок.

Сподобався урок?

Придбайте повний курс, щоб отримати доступ до всіх уроків.

Перейти до курсу