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.

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.
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:
| Wersja | W npm | Co przyniosła |
|---|---|---|
| 18.3.1 | kwi 2024 | Ostatni 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.0 | 5 gru 2024 | Actions (otwiera się w nowej karcie), useActionState, useFormStatus, useOptimistic, use, ref jako prop, metadane dokumentu, stabilne Server Components |
| 19.1.0 | 28 mar 2025 | Owner Stack, poprawki Suspense i hydratacji (otwiera się w nowej karcie) |
| 19.2.0 | 1 paź 2025 | <Activity>, useEffectEvent, cacheSignal (otwiera się w nowej karcie), Performance Tracks, częściowy prerendering |
| 19.3.0 | 9 wrz 2026 | Stabilne <ViewTransition> i Fragment Refs (otwiera się w nowej karcie), browser(), Trusted Types, <Context> w Server Components |
| 19.3.1 | 14 paź 2026 | Jedna 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 Router | Pages Router | |
|---|---|---|
| Jaki React działa | Kanarkowy React wbudowany w Next.js | react i react-dom, które instalujesz |
| Jak zmienić działającego Reacta | Aktualizacja next | Aktualizacja 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ę:
"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 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
"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>;}Pracę dzielą trzy hooki i działanie każdego widać w demo:
useOptimisticwstawia 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.useFormStatuszmienia 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.useActionStatetrzyma 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 zwracaerror: 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ą
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's time, when the answer arrives. </p> </> );}Strona to Server Component, więc jej version to React, który renderuje na serwerze. Wiersz przeglądarki pochodzi z małego Client Component:
"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";}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
Zaktualizuj Next.js i Reacta razem
Uruchom
npm install next@latest react@latest react-dom@latest, a przy TypeScripcie także@types/ireact @types/. 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.react-dom 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/z przewodnika aktualizacji Reacta (otwiera się w nowej karcie).19/ migration-recipe Sprawdź, który React działa
Wypisz
versionzreactw Server Component i w Client Component, tak jak demo. W App Routerze oba pokażą build kanarkowy z Twojej wersji Next.js.Napisz Server Function
Umieść funkcję asynchroniczną w pliku zaczynającym się od
"use server". ZuseActionStateprzyjmuje poprzedni stan i dane formularza, a zwraca następny stan, razem z błędami.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.Dodaj useFormStatus i useOptimistic
Przycisk wysyłki umieść w osobnym komponencie, który wywołuje
useFormStatus(). Setter zuseOptimisticwywołaj w akcji, zanim zaczekasz na serwer.Przetestuj build produkcyjny
Uruchom
next buildinext starti 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/; 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.
