Menu

React 19: tính năng mới, API bị loại bỏ và cách nâng cấp

React 19 bổ sung Actions, useActionState, useOptimistic, use, ref như một prop và metadata cho tài liệu, còn 19.2 thêm Activity và useEffectEvent. Xem từng tính năng chạy trực tiếp, những gì đã bị loại bỏ và cách nâng cấp.

Trang này có trình soạn thảo chạy trực tiếp. Sửa, chạy và xem đầu ra ngay lập tức.

React 19 là phiên bản lớn của React, phát hành vào tháng 12 năm 2024. Nó bổ sung Actions (các hàm async quản lý trạng thái chờ, lỗi và form), các hook useActionState, useOptimistic và use, ref như một prop thông thường, cùng các thẻ <title> và <meta> được React chuyển vào head của tài liệu. React 19.2 (tháng 10 năm 2025) thêm <Activity> và useEffectEvent.

Mọi ví dụ bên dưới đều chạy trên React 19.2. Đây là một Action: một hàm async được truyền cho form, với trạng thái chờ và lỗi trả về được useActionState xử lý.

Nhấn Save khi ô còn trống để xem lỗi, rồi gõ một cái tên và lưu: nút hiển thị "Saving..." trong 800 ms. Không có useState cho lỗi, không có cờ isLoading và không có e.preventDefault().

Actions và form action

Trong React 18, với mỗi form bạn đều viết cùng những bước: chặn submit mặc định, bật cờ loading, await request, lưu lỗi, tắt cờ. React 19 gọi một hàm làm việc async bên trong transition là một Action, và tự lo phần sổ sách đó cho bạn.

  • startTransition (và useTransition) giờ nhận một hàm async. isPending giữ giá trị true cho đến khi cả hàm chạy xong.
  • <form action={fn}> gọi fn với FormData của form khi form được submit. Nó chạy như một Action, và sau khi chạy xong React đặt lại các trường uncontrolled của form.
  • <button formAction={fn}> cho một nút submit có action riêng.
  • useActionState giữ giá trị mà action trả về gần nhất, nên một action có thể trả về thông báo lỗi hoặc bản ghi đã lưu.
  • useFormStatus từ react-dom cho phép một component bên trong form biết form đó có đang submit hay không, mà không cần truyền props xuống. Nó cần một <form> cha, nên ở đây nó xuất hiện trong một khối code tĩnh:
import { useFormStatus } from 'react-dom';

function SubmitButton() {
    const { pending } = useFormStatus();
    return <button disabled={pending}>{pending ? 'Sending...' : 'Send'}</button>;
}

useOptimistic

useOptimistic hiển thị kết quả bạn mong đợi trong lúc Action vẫn đang chạy, và quay về state thật khi Action kết thúc. Một bộ đếm lượt thích có thể tăng ngay khi bạn nhấn, rồi giảm lại nếu request thất bại.

const [optimisticLikes, addOptimisticLike] = useOptimistic(likes, (current, delta) => current + delta);

Trang useOptimistic có một ví dụ chạy được với API giả cố tình thất bại, để bạn xem quá trình hoàn tác.

API use

use đọc giá trị từ một promise hoặc từ một context. Với promise, nó suspend component cho đến khi promise resolve, và trong lúc đó <Suspense> gần nhất hiển thị fallback. Khác với mọi hook khác, use có thể được gọi bên trong if hay vòng lặp, và sau một lệnh return sớm.

React 19 cũng cho phép bạn render trực tiếp <ThemeContext value="dark"> thay vì <ThemeContext.Provider>. Cả hai đều xuất hiện trong ví dụ này:

ref như một prop, và cleanup cho ref

Function component giờ nhận ref như mọi prop khác. Bạn không còn cần bọc nó trong forwardRef để chuyển một ref xuống DOM element.

Ref callback giờ cũng có thể trả về một hàm cleanup. React gọi hàm đó khi element rời khỏi màn hình, giống cách cleanup của effect hoạt động. Một callback không trả về gì vẫn được gọi với null khi bị gỡ bỏ, như trong React 18.

Nhấn nút vài lần và đọc console: mỗi lần gỡ bỏ ghi dòng cleanup, mỗi lần quay lại ghi attached to DIV.

Metadata cho tài liệu

Bạn có thể render <title>, <meta> và <link> ở bất kỳ đâu trong component, và React chuyển chúng vào <head>. Một component trang có thể tự đặt tiêu đề mà không cần thư viện như react-helmet.

Bản xem trước không có tab trình duyệt để hiển thị, nên effect ghi log document.title thay vào đó. Chuyển bài viết và tiêu đề được log thay đổi theo.

Stylesheet cũng được xử lý tương tự: <link rel="stylesheet" href="..." precedence="default" /> bên trong một component được chèn vào head đúng một lần, theo thứ tự precedence, và React chờ nó tải xong rồi mới hiển thị nội dung cần đến nó. Một <script async src="..."> được nhiều component render chỉ tải một lần. react-dom cũng export preload, preinit, preconnect và prefetchDNS để gợi ý tải tài nguyên.

Activity và useEffectEvent (React 19.2)

<Activity mode="hidden"> ẩn các phần tử con mà không vứt bỏ state của chúng. React ẩn DOM, chạy cleanup của các effect và khôi phục mọi thứ khi mode trở lại "visible". Nó hợp với các tab và panel mà bạn đoán người dùng sẽ quay lại.

Gõ một ghi chú, chuyển sang About rồi quay lại. Chữ vẫn còn đó, và console cho thấy effect đã được cleanup trong lúc bị ẩn. Thay wrapper <Activity> bằng {tab === 'notes' && <Notes />}, ghi chú sẽ mất mỗi lần chuyển tab.

useEffectEvent đưa một hàm ra khỏi danh sách dependency của effect. Hàm đó luôn thấy props và state mới nhất, nhưng việc chúng thay đổi không khiến effect chạy lại:

function ChatRoom({ roomId, theme }) {
    const onConnected = useEffectEvent(() => {
        showNotification('Connected!', theme);
    });

    useEffect(() => {
        const connection = createConnection(roomId);
        connection.on('connected', () => onConnected());
        connection.connect();
        return () => connection.disconnect();
    }, [roomId]); // theme is not a dependency
}

19.2 cũng thêm cacheSignal cho Server Components (nó cho bạn biết khi nào kết quả của cache() không còn cần nữa) và Performance Tracks trong panel performance của Chrome DevTools. React 19.1 thêm captureOwnerStack, một hàm chỉ có trong môi trường development, trả về những component đã render component hiện tại.

Server Components và Server Functions

Server Components là những component chạy trước trên máy chủ (hoặc lúc build) và gửi kết quả đến trình duyệt. Chúng có thể là async và đọc trực tiếp cơ sở dữ liệu, và code của chúng không bao giờ được gửi xuống client. Server Functions (ban đầu gọi là Server Actions) là các hàm async được đánh dấu bằng 'use server' mà một client component có thể gọi như một hàm bình thường. Cả hai đều cần một framework có bundler hỗ trợ chúng, chẳng hạn Next.js App Router, nên chúng không chạy được trong trình soạn thảo này.

// A Server Component: async, runs on the server only
export default async function Notes() {
    const notes = await db.notes.findMany();
    return notes.map((note) => <Note key={note.id} note={note} />);
}

// A Server Function, usable as a form action
async function createNote(formData) {
    'use server';
    await db.notes.create({ text: formData.get('text') });
}

Các API bị loại bỏ và thay đổi

React 19 loại bỏ những API đã bị deprecate từ nhiều năm:

Bị loại bỏDùng thay thế
ReactDOM.render, ReactDOM.hydratecreateRoot, hydrateRoot từ react-dom/client
unmountComponentAtNoderoot.unmount()
findDOMNodemột ref trên DOM element
String ref (ref="input")useRef hoặc một ref callback
Legacy context (contextTypes, getChildContext)createContext với static contextType hoặc use
Kiểm tra propTypes (giờ bị bỏ qua mà không báo gì)TypeScript, hoặc tự viết kiểm tra
defaultProps trên function componentgiá trị mặc định của tham số
react-dom/test-utilsact từ react; React Testing Library cho phần còn lại
react-test-renderer/shallowpackage react-shallow-renderer
React.createFactoryJSX

Class component vẫn giữ defaultProps. Lỗi cũng được báo theo cách khác: lỗi bị error boundary bắt được ghi bằng console.error một lần, lỗi không được bắt đi đến window.reportError, và createRoot nhận các tùy chọn onCaughtError và onUncaughtError để bạn tự báo lỗi.

Nâng cấp lên React 19

Hãy nâng cấp lên React 18.3 trước. Phiên bản này giống hệt 18.2 nhưng cảnh báo về các API đã bị deprecate và những thay đổi khác mà React 19 cần, để bạn sửa chúng trong lúc ứng dụng vẫn chạy. React 19 cũng yêu cầu JSX transform hiện đại, thứ mà Vite và mọi framework hiện nay đều đã dùng. Sau đó cài React 19:

npm install react@^19 react-dom@^19
npm install --save-dev @types/react@^19 @types/react-dom@^19

Hướng dẫn nâng cấp chính thức chỉ đến các codemod cho những thay đổi máy móc. Codemod đầu tiên xử lý string ref, lệnh import act và ReactDOM.render; codemod thứ hai cập nhật code TypeScript theo các kiểu mới:

npx codemod@latest react/19/migration-recipe
npx types-react-codemod@latest preset-19 ./src

Sau khi nâng cấp, không có gì buộc bạn phải dùng Actions hay các hook mới. Các component, hook và class component hiện có vẫn tiếp tục chạy; bạn có thể chuyển từng form sang <form action> một.

Câu hỏi thường gặp

React 19 được phát hành khi nào?

React 19 ra bản ổn định vào tháng 12 năm 2024. React 19.1 ra mắt vào tháng 3 năm 2025 và React 19.2 vào tháng 10 năm 2025.

React 19 có những thay đổi lớn nào?

Actions (các hàm async tự lo trạng thái chờ, lỗi và form cho bạn), các hook useActionState, useOptimistic và use, ref như một prop bình thường, <Context> dùng làm provider, cùng các thẻ <title> và <meta> được chuyển vào head của tài liệu. Server Components đã ổn định cho các framework.

forwardRef có bị deprecate trong React 19 không?

Function component giờ có thể nhận ref như một prop thông thường, nên code mới không cần forwardRef. Nó vẫn chạy được, và đội ngũ React cho biết nó sẽ bị deprecate trong một phiên bản tương lai.

React 19 có làm hỏng ứng dụng React 18 đang có không?

Chủ yếu qua các API đã bị loại bỏ: ReactDOM.render, findDOMNode, string ref, legacy context, propTypes và defaultProps trên function component. React 19 cũng yêu cầu JSX transform hiện đại. Hãy nâng cấp lên React 18.3 trước, sửa các cảnh báo deprecate của nó, rồi chạy các codemod của React 19.

Có cần Next.js để dùng React 19 không?

Không. Actions, các hook mới, ref như một prop và metadata đều chạy trong một ứng dụng client thuần dựng bằng Vite. Server Components và Server Functions cần một framework hỗ trợ chúng, chẳng hạn Next.js.

Hình minh họa các ngôn ngữ lập trình của Coddy

Học lập trình cùng Coddy

Bắt đầu