· react / react-19 / frontend

React 19 — đánh giá production 2026: nâng cấp hay chờ?

Nâng cấp React 19. Server Components cải thiện TTFB thực sự, compiler loại bỏ memoization thủ công, và migration tốn ba ngày chứ không phải ba tuần.

Bởi Ethan

2.733 từ · 14 phút đọc

Nâng cấp. React 19 là bước chuyển DX lớn nhất kể từ hooks. Các con số hiệu năng là thật, compiler loại bỏ một nhóm lỗi thực sự, và codemod migration gánh phần lớn công việc nặng nhọc. Nếu bạn vẫn đang dùng React 18, không còn lý do chính đáng nào để chờ thêm nữa.

Bài này dành cho ai

Các kỹ sư đang chạy React 18 trong production, đã theo dõi hệ sinh thái React 19 ổn định dần và muốn có đánh giá thực tế về việc nâng cấp có đáng gây ra xáo trộn hay không. Nếu bạn đang bắt đầu dự án mới, hãy bắt đầu bằng React 19 — bài này dành cho quyết định migration.

Những gì React 19 đã ra mắt

React 19.0 ra mắt ngày 5 tháng 12 năm 2024. React 19.2 tiếp theo vào ngày 1 tháng 10 năm 2025. Khoảng cách này quan trọng: React Compiler đạt v1.0 cùng tuần — phiên bản production-stable đầu tiên, đã được kiểm chứng trong production ở Meta — và một số điểm thô của Server Components đã được xử lý.

Các tính năng chủ đạo:

  • Server Components — component render phía server, không gửi JavaScript xuống client mặc định
  • Server Actions — hàm async có annotation 'use server' chạy phía server, tích hợp trực tiếp với form
  • useActionState — thay thế useReducer cùng code xử lý form state thủ công cho form có server backend
  • useOptimistic — cập nhật UI lạc quan, tự revert khi xảy ra lỗi
  • React Compiler (v1.0, production-stable) — memoization tự động, không cần useMemo/useCallback thủ công
  • Ref as propforwardRef đã bị loại bỏ; ref truyền qua props như mọi prop khác
  • Native <title><meta> — metadata document từ component tree, không cần react-helmet
  • Asset preloading APIspreload, preinit, prefetchDNS như các lệnh gọi React native

Changelog chính thức của React 19 đề cập tất cả. Điều changelog không thể nói là tính năng nào thực sự tạo ra khác biệt trong production.

Server Components: các con số là thật, nhưng sự chuyển đổi tư duy không nhỏ

Bài thử nghiệm production ba tuần của Elvis Sautet đo được cải thiện TTFB 57% ở trang chủ và 93% ở trang sản phẩm sau khi chuyển sang Server Components. Đây là kết quả tự báo cáo từ một app production không tên, không có thông tin về thông số máy chủ, mô tả workload, hay cỡ mẫu — hãy coi các con số cụ thể là định hướng, không phải dữ liệu chính xác. Xu hướng nhất quán qua các báo cáo: khi bạn ngừng gửi component tree dưới dạng JavaScript và bắt đầu gửi HTML, TTFB giảm.

Cơ chế rất rõ ràng. Một Server Component render tại request time trên server. Không có JavaScript nào được gửi xuống client cho component đó. Browser nhận HTML. TTFB giảm vì client không phải chờ tải, parse, và thực thi bundle trước khi hiển thị bất cứ thứ gì.

Nhưng sự chuyển đổi tư duy là thật và không nhỏ. Server Components không phải là lớp tối ưu hóa có thể nhúng vào code hiện có. Chúng là một ranh giới kiến trúc. Server Component không thể dùng useState, useEffect, hay bất kỳ browser API nào. Client Component ('use client') có thể dùng những thứ đó, nhưng nó đưa JavaScript về phía client trở lại. Ranh giới là tường minh và một chiều — bạn có thể truyền output của Server Component vào Client Component dưới dạng children, nhưng không thể theo chiều ngược lại.

Các team thử migrate từng component một, rắc annotation 'use server' với hy vọng thu lợi nhanh, đều báo cáo nhầm lẫn và regression. Những team thấy lợi nhuận thực sự đã tiếp cận nó như một quyết định kiến trúc data-fetching trước tiên: xác định component nào chỉ hiển thị, component nào cần tương tác, và vẽ đường ranh giới server/client một cách có chủ ý.

Nếu app của bạn tương tác nặng (dashboard, real-time UI, form-heavy workflow), Server Components mang lại ít hơn. Nếu app của bạn có nhiều trang đọc nặng — trang sản phẩm, danh sách bài viết, profile — mức cải thiện là đáng kể.

Tài liệu App Router của Vercel có giải thích rõ nhất về ranh giới server/client hiện có.

Nếu bạn đang cân nhắc Next.js so với framework khác cho dự án RSC-first, SvelteKit vs Next.js 2026 so sánh routing, độ trưởng thành RSC, và hiệu năng build giữa hai framework.

Form không còn boilerplate

useActionState là phần của React 19 sẽ tạo ra khác biệt lớn nhất trong công việc hàng ngày cho hầu hết team. Đây là cách một form có server backend trông như thế nào trong React 18:

function ContactForm() {
  const [pending, setPending] = useState(false);
  const [error, setError] = useState<string | null>(null);

  async function handleSubmit(e: React.FormEvent<HTMLFormElement>) {
    e.preventDefault();
    setPending(true);
    setError(null);
    const formData = new FormData(e.currentTarget);
    const result = await submitContact(formData);
    if (!result.ok) setError(result.message);
    setPending(false);
  }

  return (
    <form onSubmit={handleSubmit}>
      {error && <p>{error}</p>}
      <button disabled={pending}>{pending ? 'Sending...' : 'Send'}</button>
    </form>
  );
}

Tương đương trong React 19:

'use server';
async function submitContact(prevState: unknown, formData: FormData) {
  const result = await db.contact.create({ data: Object.fromEntries(formData) });
  if (!result.ok) return { error: result.message };
  return { success: true };
}

// Trong file component:
'use client';
import { useActionState } from 'react';

function ContactForm() {
  const [state, action, pending] = useActionState(submitContact, null);

  return (
    <form action={action}>
      {state?.error && <p>{state.error}</p>}
      <button disabled={pending}>{pending ? 'Sending...' : 'Send'}</button>
    </form>
  );
}

Code thừa biến mất. Không còn preventDefault thủ công, không còn useState cho pending state, không còn submit handler riêng. Thuộc tính action trên thẻ <form> native kết nối tất cả lại.

Phạm vi này bao gồm khoảng 70% trường hợp form thực tế — những form gửi dữ liệu lên server và hiển thị kết quả. Với 30% còn lại, React Hook Form vẫn là câu trả lời đúng. Form nhiều bước phức tạp, schema validation phía client, field array, logic field có điều kiện, theo dõi trạng thái dirty của form — RHF xử lý tất cả tốt hơn useActionState thuần. Pattern kết hợp đang nổi lên: Server Actions cho tầng submission, RHF cho tầng validation phía client và UX.

Vị thế của Formik trong hệ sinh thái đã yếu đi đáng kể — cộng đồng đang dịch chuyển khỏi nó — nhưng tình trạng bảo trì của nó là câu hỏi riêng biệt so với tính phù hợp kỹ thuật với code hiện có của bạn.

Hiệu ứng compiler: tạm biệt useMemo?

React Compiler v1.0 tự động áp dụng memoization cho các component và giá trị được hưởng lợi từ nó. Bạn viết component như thể memoization không tồn tại. Compiler quyết định khi nào cần bọc.

Kết quả production từ thông báo v1.0: Meta Quest Store thấy tải ban đầu nhanh hơn lên đến 12% và một số tương tác nhanh hơn trên 2.5 lần; Sanity Studio tăng 20–30% frame rate render tốt hơn (từ case study cộng đồng của họ); Wakelet đo được cải thiện LCP 10% và ~15% INP (từ case study cộng đồng của họ). Mức lợi tùy thuộc vào mức độ bạn đang dùng memoization trong codebase hiện tại.

Lợi ích là thật và lớn. useMemo không cần thiết là một trong những nguồn lỗi phổ biến nhất trong React codebase: mảng dependency sai, over-memoization phá vỡ referential equality, memoization chạy tốn hơn cả re-render mà nó đang ngăn chặn. Compiler làm cho những lỗi đó không thể xảy ra theo nhóm.

Ràng buộc rất nghiêm. Compiler yêu cầu mỗi component và hook phải tuân theo Rules of Hooks mà không có ngoại lệ. Code hoạt động được dưới runtime enforcement của React 18 — hook được gọi có điều kiện theo cách tình cờ an toàn, shortcut dependency array chưa bao giờ được kích hoạt — sẽ bị từ chối hoặc compile sai. Migration linter gắn cờ những trường hợp này, nhưng bạn cần phải sửa chúng.

Third-party library là yếu tố không thể đoán trước. Library dùng hook theo cách không chuẩn không tự động tương thích với compiler. Kiểm tra dependency tree trước khi bật toàn bộ. Tài liệu React Compiler đề cập những gì cần kiểm tra và ghi lại các hạn chế đã biết — đọc trước khi bật compiler, không phải sau.

Lộ trình rollout thận trọng: bật compiler trên một route hoặc component subtree, theo dõi render với React DevTools Profiler panel (nay hiển thị các quyết định compiler), mở rộng dần.

API nhỏ, tác động lớn

Ba bổ sung nhỏ dễ bị đánh giá thấp:

Ref as prop. forwardRef đã bị loại bỏ. Component trước đây cần:

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

Nay trở thành:

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

Với các component library expose forwardRef trên mỗi leaf component, đây là đơn giản hóa có ý nghĩa. Lớp wrapper indirection biến mất, TypeScript type trở nên đơn giản hơn, và debug dễ hơn vì component có tên thật trong stack trace.

Native <title><meta>. Bạn có thể render tag <title><meta> từ bất kỳ component nào trong tree và React sẽ hoist chúng lên <head>. Đây không phải là thay thế hoàn toàn cho react-helmet trong app phức tạp — bạn vẫn cần logic deduplication cho các tag có cùng tên — nhưng nó loại bỏ dependency này cho 80% trường hợp của single-page hoặc metadata được Next.js quản lý.

Asset preloading APIs. preload('/fonts/inter.woff2', { as: 'font' })preinit('/analytics.js', { as: 'script' }) cho bạn kiểm soát lập trình cascade <link rel="preload"> từ code component. Trước đây bạn làm điều này qua framework-specific API hoặc inject thủ công vào <head>. Các phiên bản React-native được dedup tự động qua concurrent render.

Migration: những gì thực sự bị vỡ và mất bao lâu

Dựa trên các báo cáo migration thực tế: ba đến bốn ngày cho một app production điển hình, phần lớn tự động qua codemod. Repo react-codemod liệt kê tất cả transform có sẵn — chạy từng cái theo tên thay vì một sweep, để bạn review từng thay đổi trước khi commit.

Codemod xử lý phần lớn thay đổi cơ học: forwardRef → prop, loại bỏ deprecated lifecycle, ReactDOM.rendercreateRoot (nếu bạn bằng cách nào đó bỏ lỡ điều này trong React 18), và nhiều rename API nhỏ hơn.

Những gì codemod không xử lý — và gây ra ma sát thực sự trong các báo cáo migration:

Thay đổi prefix useId. React 19 thay đổi định dạng prefix của string do useId tạo ra. Các team dùng output useId trong CSS selector (ví dụ, #${id}-input như target của selector :has()) có selector bị vỡ âm thầm. Cách sửa mang tính cơ học một khi bạn biết pattern, nhưng tìm tất cả các instance mất thời gian. Một team báo cáo commit sửa 2,847 file — phần lớn là output codemod — với khoảng 30 sửa thủ công ở tầng CSS.

Tương thích third-party library. Animation library, form library, và component kit phụ thuộc vào hành vi React nội bộ có timeline cập nhật khác nhau. framer-motionreact-spring đều ra phiên bản tương thích React 19 trong vài tuần sau khi release stable. Các package ít được bảo trì hơn mất nhiều thời gian hơn hoặc cần thay thế. Kiểm tra node_modules về tương thích React 19 trước khi bắt đầu — kiểm tra changelog và trang npm của từng library trực tiếp để tìm tuyên bố tương thích React 19.

Thay đổi hành vi Strict Mode. React 19 mở rộng hành vi double-invocation của Strict Mode. Code có side effect trong render phase mà tình cờ cancel out đúng cách nay bộc lộ rõ những side effect đó. Đây là hành vi đúng được phơi bày, không phải regression, nhưng đòi hỏi phải sửa.

Xử lý lỗi cho người dùng Sentry. React 19 thay đổi error boundary API — cụ thể, onErroronCaughtError trên <ErrorBoundary>. Sentry React SDK 8 hỗ trợ các hook mới. Nếu bạn đang dùng Sentry React SDK 7, nâng cấp nó trước hoặc cùng lúc với migration React 19, không phải sau — các error capture hook của SDK 7 sẽ bỏ sót lỗi được throw trong Server Actions.

Các authentication flow dùng Server Actions cũng thay đổi hình dạng. Nếu bạn dùng Clerk cho auth, package @clerk/nextjs phiên bản 5+ xử lý Server Actions native. Pattern middleware vẫn như cũ; việc xử lý session token trên Server Actions là tự động.

Nên nâng cấp ngay hay chờ

Nếu team bạn vẫn đang lựa chọn frontend framework, React vs Svelte 2026React vs Vue 2026 so sánh chi tiết trước khi cam kết migration path React 19.

Nâng cấp ngay nếu:

  • App của bạn có nhiều trang đọc nặng được hưởng lợi từ Server Components (trang sản phẩm, marketing, nội dung)
  • Bạn đang bắt đầu dự án mới
  • Bạn đang chạy Next.js 14+ App Router (bạn đã ở kiến trúc RSC rồi; nâng cấp React 19 chủ yếu là bump dependency)
  • Bạn có app nhiều form và muốn giảm code form state phía client

Chờ nếu:

  • App của bạn phụ thuộc vào third-party library chưa có thông báo tương thích React 19
  • Bạn đang giữa chu kỳ của một tính năng lớn và không thể chịu đựng regression nào trong bốn đến sáu tuần tới
  • App của bạn chủ yếu real-time, tương tác, và client-state-heavy — ROI của Server Components sẽ thấp, nên tỷ lệ chi phí/lợi ích migration kém thuận lợi hơn

Bạn có thể chờ vô thời hạn nếu:

  • App React 18 của bạn ổn định, có hiệu năng tốt, và bạn không có lý do cụ thể để thay đổi. React 18 vẫn nhận security patch. Nâng cấp đáng làm với hầu hết team, không phải tất cả.

Kết luận

React 19.2 là phiên bản để nâng cấp lên. Compiler một mình đã đáng để upgrade với app có memoization surface area đáng kể. Server Components đáng làm nếu kiến trúc của bạn có hình dạng phù hợp — và sự rõ ràng kiến trúc buộc bạn trả lời câu hỏi đó có giá trị ngay cả khi lợi nhuận hiệu năng là khiêm tốn.

Migration tốn ba đến bốn ngày engineering cho app mid-size điển hình, với codemod gánh phần lớn công việc. Rủi ro là thật (third-party library, CSS coupled với output useId, Strict Mode side effect) nhưng có thể đoán trước. Audit trước, migrate trong feature branch, nâng cấp Sentry và auth lib cùng với React chứ không phải sau.

Lưu ý

Số liệu TTFB của Elvis Sautet là từ bài test production tự báo cáo kéo dài ba tuần trên một app production không tên, không có thông tin về thông số máy chủ, mô tả workload, hay cỡ mẫu — nguồn (một bài dev.to cá nhân) được dẫn link trực tiếp. Số liệu Meta Quest Store là từ thông báo React Compiler 1.0; số liệu Sanity Studio và Wakelet là từ các case study cộng đồng của họ được dẫn link trong bài đó. Kết quả thực tế sẽ khác nhau tùy codebase.

Ngày ra mắt React 19.1 được ghi là giữa năm 2025 trong một số bản tóm tắt cộng đồng; toolchew không thể xác minh điều này qua nguồn chính và đã bỏ qua dữ liệu điểm đó.

Toolchew nhận hoa hồng affiliate từ Vercel, Sentry, và Clerk qua các liên kết trong bài viết này. Điều này không ảnh hưởng đến kết luận. Cả ba đều được đánh giá độc lập với tư cách affiliate của họ.

Tài liệu tham khảo