React 19 w Next.js: Actions i wersja Reacta, która działa

React 19 jest stabilny od 5 grudnia 2024, najnowszy to 19.3.1. Demo na Next.js 16 pokazuje Actions i to, że App Router ma własnego Reacta, nie z package.json.

Czas czytania: 7 min czytaniaOpublikowano:

React 19 jest stabilny od 5 grudnia 2024, a najnowsze wydanie to 19.3.1 z 14 października 2026. Żeby używać go w Next.js, wybierz App Router w Next.js 15 lub nowszym: zainstaluj next@latest react@latest react-dom@latest, a formularze pisz jako React 19 Actions, czyli funkcję z "use server" za useActionState, z useFormStatus dla przycisku w trakcie wysyłki i useOptimistic dla natychmiastowej reakcji. Jedno zaskakuje większość zespołów: App Router nie uruchamia Reacta z Twojego package.json. Nasze demo ma w package.json wersję react@19.3.1, ale działa na Next.js 16.4.3, którego wbudowany React to według informacji o wydaniach Next.js wersja kanarkowa 19.3.0-canary-278794d7-20261002, a demo wypisuje wersję Reacta, który renderuje. Każdą datę sprawdziliśmy w rejestrze npm, a każde API w dokumentacji Reacta i Next.js 5 listopada 2026; siedem testów w Playwright sprawdza, co robi demo. O tym, co gdzie działa między tymi komponentami, piszemy w tekście React Server Components: co trafia do przeglądarki.

Dodaj notatkę: od razu pojawia się z dopiskiem sending…, przycisk przez 1,5 sekundy pokazuje Adding…, a potem notatka dostaje status saved z czasem serwera. Dwa wiersze nad formularzem podają build Reacta, który naprawdę uruchamia App Router. · Next.js 16.4.3Otwórz demoZobacz kod

React 19: data wydania i wersje

React 19 to wersja major, na którą nakładają się kolejne wydania minor. Daty poniżej pochodzą z rejestru npm (otwiera się w nowej karcie) (UTC), odczytane 5 listopada 2026:

WersjaW npmCo przyniosła
18.3.1kwi 2024Ostatni React 18: 18.2 z ostrzeżeniami o tym, co usuwa 19, według przewodnika aktualizacji do React 19 (otwiera się w nowej karcie)
19.0.05 gru 2024Actions (otwiera się w nowej karcie), useActionState, useFormStatus, useOptimistic, use, ref jako prop, metadane dokumentu, stabilne Server Components
19.1.028 mar 2025Owner Stack, poprawki Suspense i hydratacji (otwiera się w nowej karcie)
19.2.01 paź 2025<Activity>, useEffectEvent, cacheSignal (otwiera się w nowej karcie), Performance Tracks, częściowy prerendering
19.3.09 wrz 2026Stabilne <ViewTransition> i Fragment Refs (otwiera się w nowej karcie), browser(), Trusted Types, <Context> w Server Components
19.3.114 paź 2026Jedna zmiana, Improve transport protocol (otwiera się w nowej karcie) w Server Components, wersja, którą opisana niżej podatność podaje jako poprawioną

19.3.1 ma w npm tag latest. Łata krytyczną podatność Unauthenticated Remote Code Execution in React Server Components (otwiera się w nowej karcie), opublikowaną tego samego dnia. Dotyczy ona pakietów react-server-dom-webpack, -turbopack i -parcel od 19.0.0 do 19.3.0, a poprawki są w 19.0.9, 19.1.10, 19.2.9 i 19.3.1. Nasz przegląd z 18 października opisuje krytyczne RCE w React Server Components i poprawki Next.js z tego samego dnia. Strona wersji Reacta (otwiera się w nowej karcie) wciąż podaje 19.3 jako najnowszą wersję i 19.3.0 jako najnowszy wpis, więc strony, które ją przepisują, są o jedno wydanie w tyle. W sprawie wersji źródłem, któremu warto ufać, jest npm.

Czy Next.js obsługuje React 19?

Tak, a to router decyduje, którego Reacta dostajesz. Dokumentacja Next.js w części o obsłudze wersji Reacta (otwiera się w nowej karcie) mówi, że App Router używa wydań kanarkowych Reacta wbudowanych w Next.js, a Pages Router wersji zainstalowanej w package.json. Przewodnik aktualizacji do Next.js 15 (otwiera się w nowej karcie) ustawił 19 jako minimalną wersję react i react-dom.

App RouterPages Router
Jaki React działaKanarkowy React wbudowany w Next.jsreact i react-dom, które instalujesz
Jak zmienić działającego ReactaAktualizacja nextAktualizacja react i react-dom

W demo widać, który z nich renderuje. Jego Server Component wypisuje version z react podczas renderowania strony na serwerze, a Client Component wypisuje ją jeszcze raz, gdy React w przeglądarce skończy hydratację, choć package.json laboratorium prosi o react@19.3.1, jak mówi komentarz w page.tsx. Build nazywają informacje o wydaniu Next.js 16.4.0 (otwiera się w nowej karcie): „Upgrade React from 8b0da1c6-20260922 to 278794d7-20261002”. Informacje o wydaniach 16.4.1 (otwiera się w nowej karcie), 16.4.2 (otwiera się w nowej karcie) i 16.4.3 (otwiera się w nowej karcie) nie wymieniają po nim żadnej aktualizacji Reacta. W npm ten build to react@19.3.0-canary-278794d7-20261002 (otwiera się w nowej karcie); jego wersja ma w nazwie datę 2 października 2026, dwanaście dni przed 19.3.1. Nadal instalujesz react i react-dom, tak jak każe polecenie z przewodników aktualizacji Next.js, ale w demo wersja z package.json nie jest tą, która renderuje.

Jak działają React 19 Actions w demo

Action (akcja) w języku Reacta 19 to funkcja asynchroniczna uruchamiana w transition, dzięki czemu React sam śledzi jej stan oczekiwania, błędy i aktualizacje optymistyczne. Przekaż ją do propsa action elementu <form>, a React uruchomi ją w transition z danymi formularza. Server Function (otwiera się w nowej karcie) to funkcja asynchroniczna z "use server", którą wywołuje Client Component, a wykonuje serwer; przekazana do propsa action albo wywołana w akcji to według dokumentacji Reacta Server Action, i tej nazwy używa Next.js.

Server Function

Server Function w demo czeka 1,5 sekundy, co zastępuje powolny zapis do bazy, i zwraca nową listę:

app/demos/react-19/actions.ts
"use server"; export type Note = { id: string; text: string; savedAt: string };export type NotesState = { notes: Note[]; error: string | null }; // A Server Function for useActionState: it gets the previous state first, then the form's// data, and what it returns becomes the new state in the browser. `previous` comes from the// browser, so a real app would read and write its notes in a database instead.export async function addNote(previous: NotesState, formData: FormData): Promise<NotesState> {  const text = String(formData.get("note") ?? "").trim();  if (!text) return { ...previous, error: "Write a note first." };   // Stands in for a slow write, so the pending and optimistic states stay on screen.  await new Promise((resolve) => setTimeout(resolve, 1500));   const note = { id: crypto.randomUUID(), text: text.slice(0, 40), savedAt: new Date().toISOString() };  return { notes: [note, ...previous.notes].slice(0, 3), error: null };}
Z labu, commit f663557

Z useActionState (otwiera się w nowej karcie) dostaje najpierw poprzedni stan, a potem dane formularza, a to, co zwróci, staje się nowym stanem. Przewodnik Next.js po formularzach (otwiera się w nowej karcie) mówi to samo: z useActionState sygnatura Server Function zmienia się i pierwszym argumentem jest poprzedni stan. Pusta notatka wraca od razu z błędem w tym stanie; tak błędy walidacji docierają do formularza bez rzucania wyjątku.

Formularz: useActionState, useOptimistic i useFormStatus

app/demos/react-19/notes.tsx
"use client"; import { useActionState, useOptimistic } from "react";import { useFormStatus } from "react-dom"; import { addNote, type Note, type NotesState } from "./actions";import styles from "./react-19.module.css"; const initialState: NotesState = { notes: [], error: null }; type Shown = Note | { id: string; text: string; savedAt: null }; export function Notes() {  // useActionState keeps what the last action returned: the notes the server saved, or an error.  const [state, formAction] = useActionState(async (previous: NotesState, formData: FormData) => {    const text = String(formData.get("note") ?? "").trim();    if (text) addOptimistic(text);    return addNote(previous, formData);  }, initialState);   // While the action runs, the list shows the new note too; when it ends, React drops the  // optimistic note and renders state.notes, which now holds the saved one.  const [notes, addOptimistic] = useOptimistic<Shown[], string>(state.notes, (current, text) => [    { id: `sending-${current.length}`, text, savedAt: null },    ...current,  ]);   return (    <section className={styles.notes} aria-label="Notes">      <form action={formAction} className={styles.form}>        <input name="note" aria-label="Note" placeholder="Write a note" maxLength={40} autoComplete="off" />        <SubmitButton />      </form>      {state.error && (        <p role="alert" className={styles.error}>          {state.error}        </p>      )}      <ul className={styles.list}>        {notes.map((note) => (          <li key={note.id} data-state={note.savedAt ? "saved" : "sending"}>            <span>{note.text}</span>            {note.savedAt ? (              <time dateTime={note.savedAt}>saved {note.savedAt.slice(11, 19)} UTC</time>            ) : (              <em>sending…</em>            )}          </li>        ))}      </ul>    </section>  );} // useFormStatus reads the <form> around it, so it has to sit in a child component.function SubmitButton() {  const { pending } = useFormStatus();  return <button disabled={pending}>{pending ? "Adding…" : "Add"}</button>;}
Z labu, commit f663557

Pracę dzielą trzy hooki i działanie każdego widać w demo:

  • useOptimistic wstawia notatkę na listę od razu, z dopiskiem sending…, gdy serwer jeszcze czeka. Stan optymistyczny (otwiera się w nowej karcie) jest równy przekazanej wartości, chyba że trwa Action, więc React sam usuwa tymczasową notatkę, gdy akcja się kończy.
  • useFormStatus zmienia przycisk na nieaktywny Adding…, dopóki akcja trwa, a potem z powrotem na Add. Zastrzeżenia do useFormStatus (otwiera się w nowej karcie) mówią, że czyta on tylko nadrzędny <form>, dlatego siedzi w komponencie potomnym.
  • useActionState trzyma to, co zwróciła Server Function: zapisane notatki, każdą z czasem serwera, a przy pustej notatce błąd Write a note first. i niezmienioną listę. Następna poprawna notatka zwraca error: null, co usuwa komunikat.

Formularz nie ma kodu do resetu. Dokumentacja <form> (otwiera się w nowej karcie) mówi, że React resetuje niekontrolowane pola formularza, gdy funkcja akcji zakończy się powodzeniem, a pole notatki jest tu niekontrolowane.

Strona i wiersze z wersją

app/demos/react-19/page.tsx
import { version } from "react"; import { BrowserReactVersion } from "./browser-version";import { Notes } from "./notes";import styles from "./react-19.module.css"; // A Server Component, so `version` is the React that renders on the server. The lab's// package.json asks for react 19.3.1; the App Router uses the React build that ships inside Next.js.export default function Page() {  return (    <>      <dl className={styles.versions}>        <div>          <dt>Server</dt>          <dd>            <output aria-label="React on the server">{version}</output>          </dd>        </div>        <div>          <dt>Browser</dt>          <dd>            <output aria-label="React in the browser">              <BrowserReactVersion />            </output>          </dd>        </div>      </dl>      <Notes />      <p className="hint">        Add a note. It shows up at once as sending…, the button reads Adding… while the Server Function runs (it        waits 1.5 s), and the note turns saved, with the server&apos;s time, when the answer arrives.      </p>    </>  );}
Z labu, commit f663557

Strona to Server Component, więc jej version to React, który renderuje na serwerze. Wiersz przeglądarki pochodzi z małego Client Component:

app/demos/react-19/browser-version.tsx
"use client"; import { useSyncExternalStore, version } from "react"; const subscribe = () => () => {}; // The server snapshot (null) is used on the server and during hydration, so the version shows// only once the React that runs in the browser renders this component.export function BrowserReactVersion() {  const browser = useSyncExternalStore(subscribe, () => version, () => null);  return browser ?? "not hydrated yet";}
Z labu, commit f663557

useSyncExternalStore używa migawki serwera (otwiera się w nowej karcie) (tu null) na serwerze i w czasie hydratacji, a potem renderuje się jeszcze raz z wartością z przeglądarki, więc wiersz pokazuje wersję dopiero wtedy, gdy komponent uruchomi React w przeglądarce. Skopiuj oba pliki do swojej aplikacji, żeby zobaczyć, którego Reacta ona używa.

Jak używać React 19 w aplikacji Next.js

  1. Zaktualizuj Next.js i Reacta razem

    Uruchom npm install next@latest react@latest react-dom@latest, a przy TypeScripcie także @types/react i @types/react-dom. 5 listopada 2026 dokumentacja Next.js (otwiera się w nowej karcie) podaje 16.4.5 jako najnowszą wersję, czyli Next.js 16.4.5 z poprawkami bezpieczeństwa; demo działa na 16.4.3.

  2. Z Reacta 18 przejdź przez 18.3

    W aplikacji na React 18 zaktualizuj najpierw do Reacta 18.3, popraw jego ostrzeżenia, a potem uruchom npx codemod@latest react/19/migration-recipe z przewodnika aktualizacji Reacta (otwiera się w nowej karcie).

  3. Sprawdź, który React działa

    Wypisz version z react w Server Component i w Client Component, tak jak demo. W App Routerze oba pokażą build kanarkowy z Twojej wersji Next.js.

  4. Napisz Server Function

    Umieść funkcję asynchroniczną w pliku zaczynającym się od "use server". Z useActionState przyjmuje poprzedni stan i dane formularza, a zwraca następny stan, razem z błędami.

  5. Podłącz formularz przez useActionState

    W Client Component wywołaj useActionState(action, initialState) i przekaż zwróconą funkcję do <form action>. Błędy i wyniki pokazuj ze stanu.

  6. Dodaj useFormStatus i useOptimistic

    Przycisk wysyłki umieść w osobnym komponencie, który wywołuje useFormStatus(). Setter z useOptimistic wywołaj w akcji, zanim zaczekasz na serwer.

  7. Przetestuj build produkcyjny

    Uruchom next build i next start i wyślij formularz: powinien pojawić się stan oczekiwania, optymistyczny i zapisany.

Co psuje React 19 Actions

useFormStatus w tym samym komponencie co formularz

useFormStatus czyta tylko nadrzędny <form>. Wywołaj go w komponencie, który renderuje formularz, a dokumentacja Reacta ostrzega, że pending nigdy nie będzie true (otwiera się w nowej karcie). Przenieś przycisk do komponentu potomnego, jak SubmitButton w demo.

Aktualizacja optymistyczna poza Action

Wywołaj setter z useOptimistic w zwykłym handlerze zdarzenia, a stan optymistyczny na chwilę się pojawi i zaraz wróci (otwiera się w nowej karcie) do poprzedniego, bo żadne transition go nie trzyma. Wywołuj go w funkcji przekazanej do action albo w startTransition.

Owinięcie Server Function odbiera ścieżkę bez JavaScriptu

Dokumentacja elementu form o błędach bez JavaScriptu (otwiera się w nowej karcie) mówi, że React pokaże wynik Server Function przed wczytaniem JavaScriptu tylko wtedy, gdy formularz renderuje Client Component, funkcja w jego action to sama Server Function, a wynik pokazuje useActionState. Demo owija addNote funkcją po stronie klienta, żeby najpierw wywołać setter optymistyczny, i z tego rezygnuje. Formularz rejestracji albo kontaktowy, który musi działać przed hydratacją, przekazuje Server Function do useActionState bezpośrednio i obywa się bez useOptimistic.

Ufanie temu, co wysyła przeglądarka

Poprzedni stan, który useActionState przekazuje Twojej Server Function, przychodzi z przeglądarki, tak jak dane formularza. Server Function to publiczny endpoint: przewodnik po formularzach każe sprawdzać uwierzytelnienie i uprawnienia (otwiera się w nowej karcie) w każdej Server Action, nawet na stronie widocznej tylko dla zalogowanych. Prawdziwe dane czytaj z bazy, nie ze stanu.

Stare nazwy i usunięte API

useFormState zmienił się w useActionState; stary hook jest przestarzały w React 19, jak zaznacza przewodnik aktualizacji do Next.js 15. React 19 usunął też ReactDOM.render, ReactDOM.hydrate, findDOMNode, string refs, propTypes i defaultProps w komponentach funkcyjnych, stary context i react-dom/test-utils; listę ma przewodnik aktualizacji do React 19 (otwiera się w nowej karcie). Kod w App Routerze rzadko ich używa, starsze biblioteki i testy często.

Łatanie samego react

W App Routerze podbicie react w package.json nie zmienia Reacta, który renderuje strony, bo według dokumentacji Next.js App Router używa wersji kanarkowej wbudowanej w Next.js. Październikowa podatność każe natychmiast zaktualizować pakiety react-server-dom-*, których dotyczy. App Router używa Reacta wbudowanego w Next.js, więc trzymaj next na najnowszym wydaniu, a do tego aktualne react i react-dom, których używa Pages Router.

Kiedy wyszedł React 19?

React 19.0.0 trafił do npm 5 grudnia 2024, mniej więcej dwa lata i osiem miesięcy po React 18.0.0 (29 marca 2022). Potem przyszły wersje minor: 19.1.0 28 marca 2025, 19.2.0 1 października 2025 i 19.3.0 9 września 2026.

Jaka jest najnowsza wersja Reacta?

19.3.1, opublikowana w npm 14 października 2026 i oznaczona tam jako latest, stan na 5 listopada 2026. Naprawia krytyczną podatność zdalnego wykonania kodu w pakietach React Server Components. Strona wersji Reacta wciąż podaje 19.3.0 jako najnowszy wpis, więc w tej sprawie wierz npm.

Czy Next.js obsługuje React 19?

Tak. Od Next.js 15 minimalna wersja react i react-dom to 19, a App Router używa kanarkowego buildu Reacta dostarczanego w paczce Next.js, a nie pakietu react z package.json. Next.js 16.4.3 uruchamia 19.3.0-canary-278794d7-20261002. Pages Router używa wersji, którą zainstalujesz.

Jak zaktualizować projekt do React 19?

Z Reacta 18 przejdź najpierw na 18.3: to 18.2 z ostrzeżeniami o tym, co usuwa React 19. Potem uruchom npx codemod@latest react/19/migration-recipe i zainstaluj react oraz react-dom 19 razem z typami TypeScript. W aplikacji Next.js instaluj razem z nimi next@latest, bo App Router używa Reacta wbudowanego w Next.js.

Czy React Compiler jest częścią React 19?

Nie. React Compiler to osobne narzędzie działające w czasie builda, które samo memoizuje komponenty, i obsługuje Reacta 17, 18 i 19. W Next.js instalujesz babel-plugin-react-compiler i ustawiasz reactCompiler: true w next.config.ts; od Next.js 16.0.0 to opcja najwyższego poziomu.

Dalsza lektura

React v19 (otwiera się w nowej karcie)Wpis z 5 grudnia 2024: Actions, nowe hooki, use, ref jako prop i metadane.react.dev
React 19 Upgrade Guide (otwiera się w nowej karcie)Najpierw React 18.3, potem codemody, i każde usunięte lub zmienione API.react.dev
React 19.3 (otwiera się w nowej karcie)Stabilne View Transitions i Fragment Refs, do tego browser() i Context w Server Components.react.dev
React: useActionState (otwiera się w nowej karcie)Parametry hooka, argument z poprzednim stanem i zastrzeżenia przy Server Functions.react.dev
React: useOptimistic (otwiera się w nowej karcie)Jak stan optymistyczny pokazuje się w czasie Action i dlaczego setter musi działać w jej środku.react.dev
Next.js: How to create forms with Server Actions (otwiera się w nowej karcie)Błędy walidacji z useActionState, stany oczekiwania i aktualizacje optymistyczne w App Routerze.nextjs.org
Next.js: Upgrading to version 15 (otwiera się w nowej karcie)React 19 jako minimum App Routera i useFormState przemianowany na useActionState.nextjs.org
React: Unauthenticated Remote Code Execution in React Server Components (otwiera się w nowej karcie)Podatność z 14 października 2026: których pakietów dotyczy i w których wersjach 19.x jest poprawka.github.com
Next.js i ReactReact Server Components: co trafia do przeglądarkiReact Server Components w Next.js 16 na żywym demo: co zostaje na serwerze, co trafia do przeglądarki jako JavaScript, a co niesie HTML i payload RSC.

Napisz, co budujemy.

Odpowiadamy w ciągu jednego dnia roboczego.