React Compiler 2026: Tự động Memoization và Câu hỏi Phỏng vấn

Tìm hiểu React Compiler với tự động memoization, pipeline biên dịch HIR, các quy tắc React và câu hỏi phỏng vấn thường gặp năm 2026.

React Compiler 2026 tự động memoization và câu hỏi phỏng vấn

Trong năm 2026, React Compiler đã trở thành một trong những bước tiến quan trọng nhất của hệ sinh thái React. Công cụ này giúp tự động hóa quá trình memoization mà trước đây các nhà phát triển phải thực hiện thủ công thông qua useMemo, useCallbackReact.memo. Với phiên bản ổn định v1.0 ra mắt vào tháng 10 năm 2025, React Compiler đã được Meta triển khai trên các ứng dụng production và đạt được kết quả đáng chú ý. Bài viết này phân tích chi tiết cách hoạt động của React Compiler, các quy tắc cần tuân thủ và những câu hỏi phỏng vấn thường gặp trong năm 2026.

Điểm quan trọng cần ghi nhớ

React Compiler là công cụ build-time phân tích mã nguồn và tự động chèn memoization ở cấp độ biểu thức. Nó loại bỏ nhu cầu sử dụng useMemo, useCallbackReact.memo thủ công trong phần lớn các trường hợp — nhưng không phải tất cả. Nhà tuyển dụng kỳ vọng ứng viên có thể trình bày rõ ràng cả những gì compiler xử lý được và những giới hạn của nó.

React Compiler là gì và hoạt động như thế nào?

React Compiler là trình biên dịch tối ưu hóa build-time, phân tích các component và hook của React, sau đó chèn memoization chi tiết ở những vị trí có lợi. Khác với memoization thủ công bằng useMemo hay useCallback, compiler có khả năng memoize có điều kiện và ở mức độ chi tiết hơn bất kỳ lập trình viên nào có thể duy trì bằng tay.

Compiler hoạt động như một plugin Babel (với hỗ trợ SWC ngày càng mở rộng trong Next.js 15.3.1+). Nó xử lý từng component độc lập, chuyển đổi Babel AST thành High-Level Intermediate Representation (HIR) tùy chỉnh trước khi chạy nhiều bước tối ưu hóa.

Kết quả từ production tại Meta khẳng định tác động thực tế: Quest Store có tốc độ tải ban đầu nhanh hơn tới 12% và tương tác nhanh hơn 2,5 lần. Sanity Studio báo cáo giảm 20-30% thời gian render trên 1.231 component được biên dịch.

Cấu trúc trả lời phỏng vấn: Định nghĩa compiler, giải thích rằng nó hoạt động tại thời điểm build (không phải runtime), đề cập đến pipeline HIR và trích dẫn số liệu thực tế.

Pipeline biên dịch: Từ mã nguồn đến output đã tối ưu

Câu hỏi này kiểm tra mức độ hiểu biết sâu. Pipeline của React Compiler có bảy giai đoạn riêng biệt:

  1. Source thành AST — Babel phân tích JavaScript/TypeScript thành Abstract Syntax Tree
  2. AST thành HIR — Compiler hạ AST xuống High-Level Intermediate Representation, được thiết kế riêng cho mô hình component của React
  3. Biến đổi SSA — Single Static Assignment đảm bảo mỗi biến chỉ được gán đúng một lần, cho phép theo dõi luồng dữ liệu chính xác
  4. Type Inference và Effect Analysis — Compiler phân loại các thao tác theo hiệu ứng: read, store, capture, mutate, freeze
  5. Reactive Analysis — Mỗi biểu thức được phân loại là tĩnh (hằng số, import) hoặc reactive (bắt nguồn từ props, state, context)
  6. Scope Discovery — Compiler xác định các scope memoization độc lập có thể được cache và invalidate riêng biệt
  7. Code Generation — JavaScript đã tối ưu hóa với memoization tự động được sinh ra
javascript
// Before compilation
function UserProfile({ user, theme }) {
  const fullName = user.firstName + ' ' + user.lastName;
  const style = { color: theme.primary, fontSize: 16 };
  return <div style={style}>{fullName}</div>;
}

// After compilation (simplified representation)
function UserProfile({ user, theme }) {
  const $ = useMemoCache(4);
  let fullName;
  if ($[0] !== user.firstName || $[1] !== user.lastName) {
    fullName = user.firstName + ' ' + user.lastName;
    $[0] = user.firstName;
    $[1] = user.lastName;
    $[2] = fullName;
  } else {
    fullName = $[2];
  }
  // style and JSX similarly memoized...
}

Điểm mấu chốt cho phỏng vấn: compiler thực hiện memoization ở cấp độ giá trị, không phải cấp độ component. Mỗi giá trị được tính toán có slot cache riêng, chỉ bị invalidate khi các dependency cụ thể của nó thay đổi. Mức độ chi tiết này vượt trội so với những gì useMemo đạt được trong thực tế.

Các quy tắc của React: Những giả định của Compiler

React Compiler thực hiện phân tích tĩnh với giả định rằng các component tuân theo Rules of React. Khi mã nguồn vi phạm các quy tắc này, compiler sẽ bỏ qua tối ưu hóa cho component đó — một cách âm thầm. Đây là chủ đề phỏng vấn thường xuyên.

Ba quy tắc cốt lõi:

  • Component và hook phải pure — Với cùng input, render phải tạo ra cùng output. Không được đọc hoặc ghi state mutable bên ngoài trong quá trình render.
  • Hook phải tuân theo quy ước gọi — Hook không được gọi có điều kiện, trong vòng lặp, hoặc trong hàm lồng nhau.
  • Props và state là immutable trong một lần render — Không bao giờ mutate props hoặc state trực tiếp; luôn sử dụng hàm setter.
javascript
// Rule violation: mutating during render
function BadCounter({ items }) {
  // The compiler will skip this component
  items.sort(); // Mutates the prop array!
  return <ul>{items.map(i => <li key={i}>{i}</li>)}</ul>;
}

// Correct: create a new sorted array
function GoodCounter({ items }) {
  const sorted = [...items].sort();
  return <ul>{sorted.map(i => <li key={i}>{i}</li>)}</ul>;
}
Lưu ý về hành vi bỏ qua

Khi compiler bỏ qua một component, nó không ném ra lỗi — ứng dụng vẫn hoạt động bình thường, chỉ là không có tối ưu hóa. Plugin ESLint (eslint-plugin-react-hooks với preset recommended) là cách chính để phát hiện các vi phạm này trước khi đưa lên production.

Tích hợp ESLint: Phát hiện vi phạm trước khi build

Gói eslint-plugin-react-compiler độc lập đã bị deprecated kể từ cuối năm 2025. Tất cả các quy tắc lint liên quan đến compiler hiện nằm trong eslint-plugin-react-hooks@latest.

Cấu hình với ESLint flat config:

eslint.config.jsjavascript
import reactHooks from 'eslint-plugin-react-hooks';
import { defineConfig } from 'eslint/config';

export default defineConfig([
  reactHooks.configs.flat.recommended,
]);

Các quy tắc được hỗ trợ bởi compiler phát hiện ba pattern quan trọng:

  • set-state-in-render — Gọi setState trong quá trình render, gây ra vòng lặp vô hạn
  • set-state-in-effect — Tính toán nặng bên trong effect, kích hoạt cascading re-render
  • refs — Truy cập .current trên ref trong quá trình render (ref là escape hatch mutable, không an toàn cho render)

Đối với phỏng vấn, chiến lược áp dụng được khuyến nghị: bật các quy tắc ESLint trước, sửa tất cả vi phạm, sau đó mới bật compiler. Cách tiếp cận từng bước này giảm thiểu các vấn đề bất ngờ.

Khi nào cần tối ưu hóa thủ công

Compiler không loại bỏ tất cả công việc tối ưu hóa hiệu suất. Một số kịch bản vẫn yêu cầu can thiệp thủ công:

1. Subscription tới external store

Compiler chỉ theo dõi state React, props và context. External store (Redux, Zustand, MobX) yêu cầu useSyncExternalStore hoặc cơ chế selector riêng của store để tối ưu render.

2. Tính toán nặng với tập dữ liệu lớn

Mặc dù compiler memoize giá trị trả về, nó không đánh giá chi phí thực thi. Một hàm lọc 100.000 item vẫn chạy khi dependencies thay đổi. Đối với các thao tác thực sự nặng, useMemo với dependencies rõ ràng vẫn hợp lệ — mặc dù compiler sẽ không tạo trùng lặp memoization.

3. Logic imperative dựa trên ref

Ref được cố ý loại trừ khỏi mô hình reactive của compiler. Animation, canvas drawing và tích hợp thư viện DOM bên thứ ba vẫn yêu cầu kiểm soát thủ công.

4. Memoization xuyên component

Compiler memoize trong phạm vi một component hoặc hook duy nhất. Chia sẻ giá trị được tính toán giữa các component vẫn yêu cầu lifting state, context hoặc các lớp cache bên ngoài.

javascript
// The compiler handles this automatically
function ProductCard({ product, currency }) {
  const formattedPrice = formatCurrency(product.price, currency);
  const discount = product.originalPrice - product.price;
  return (
    <div>
      <span>{formattedPrice}</span>
      {discount > 0 && <Badge>Save {discount}</Badge>}
    </div>
  );
}

// Manual optimization still needed: expensive external computation
function DataGrid({ rows }) {
  const processedRows = useMemo(
    () => rows.map(row => heavyTransform(row)), // O(n) with large n
    [rows]
  );
  return <VirtualList items={processedRows} />;
}

Sẵn sàng chinh phục phỏng vấn React / Next.js?

Luyện tập với mô phỏng tương tác, flashcards và bài kiểm tra kỹ thuật.

Cách kích hoạt React Compiler trong các Framework

Nhà tuyển dụng thường kiểm tra kiến thức thực tế về cấu hình toolchain:

Next.js (15.3.1+): Hỗ trợ native SWC. Kích hoạt trong next.config.js:

next.config.jsjavascript
const nextConfig = {
  experimental: {
    reactCompiler: true,
  },
};
export default nextConfig;

Vite 8 với @vitejs/plugin-react v6: Vì v6 đã loại bỏ Babel nội bộ để chuyển sang oxc, compiler cần @rolldown/plugin-babel:

vite.config.jsjavascript
import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';
import babel from '@rolldown/plugin-babel';
import { reactCompilerPreset } from 'babel-plugin-react-compiler';

export default defineConfig({
  plugins: [
    react(),
    babel({ presets: [reactCompilerPreset] }),
  ],
});

Expo SDK 54+: Được bật mặc định. Không cần cấu hình.

Tương thích phiên bản

React Compiler v1.0 hoạt động với React 17, 18 và 19. Tuy nhiên, toàn bộ khả năng tối ưu hóa chỉ khả dụng với React 19, nơi runtime hỗ trợ invalidation cache chi tiết thông qua useMemoCache.

So sánh React Compiler và Memoization thủ công

| Khía cạnh | React Compiler | Thủ công (useMemo/useCallback) | |-----------|----------------|-----------------------------------| | Độ chi tiết | Cấp độ giá trị, theo từng biểu thức | Cấp độ block, do lập trình viên định nghĩa | | Memoization có điều kiện | Được hỗ trợ | Không thể thực hiện | | Chi phí bảo trì | Không — tự động hoàn toàn | Cao — dependency arrays, wrapper components | | Phạm vi xuyên component | Trong phạm vi một component | Trong phạm vi một component | | External stores | Không theo dõi được | Không theo dõi được (dùng useSyncExternalStore) | | Class components | Không hỗ trợ | Không áp dụng (dùng React.memo) | | Yêu cầu build | Plugin Babel hoặc SWC | Không cần | | Hiệu suất tối đa | Giảm 20-60% re-render (thông thường) | Phụ thuộc kỹ năng lập trình viên |

Tóm tắt cho phỏng vấn: compiler tự động hóa 80-90% memoization mà lập trình viên trước đây phải xử lý thủ công, với độ chi tiết tốt hơn và không có overhead bảo trì. 10-20% còn lại liên quan đến tích hợp bên ngoài, tính toán thực sự nặng và công việc DOM imperative.

Câu hỏi phỏng vấn thường gặp

Hỏi: React Compiler hoạt động tại thời điểm build hay runtime? Build time. Compiler là plugin Babel chuyển đổi mã nguồn trong quá trình biên dịch. Output đã tối ưu sử dụng helper runtime (useMemoCache) để lưu trữ giá trị cache, nhưng toàn bộ phân tích diễn ra trước khi deployment.

Hỏi: Có nên xóa các lệnh useMemouseCallback hiện có không? Team React khuyến nghị giữ nguyên memoization thủ công hiện có. Việc xóa có thể thay đổi output biên dịch theo cách tinh tế. Đối với mã mới, hãy dựa vào compiler và chỉ thêm memoization thủ công sau khi profiling xác định nhu cầu cụ thể.

Hỏi: Điều gì xảy ra khi compiler gặp mã không thể tối ưu? Compiler âm thầm bỏ qua component hoặc hook đó. Ứng dụng vẫn hoạt động đúng — phần cụ thể đó chỉ chạy mà không có memoization tự động. Các quy tắc ESLint giúp phát hiện những trường hợp này trong quá trình development.

Hỏi: Compiler tương tác với Server Components như thế nào? Server Components chạy trên server và tạo ra output đã serialize — chúng không re-render trên client. Compiler nhắm vào client component, nơi re-render là mối quan tâm hiệu suất chính. Hai tối ưu hóa này bổ sung cho nhau: Server Components giảm bundle size, compiler giảm chi phí re-render phía client.

Hỏi: Compiler có thể tối ưu custom hook không? Có. Compiler phân tích cả component và hook. Custom hook tính toán derived state sẽ có giá trị trả về được memoize tự động, mang lại lợi ích cho mọi component sử dụng nó.

Kết luận

  • React Compiler v1.0 là công cụ build-time chèn memoization chi tiết ở cấp độ giá trị thông qua pipeline biên dịch bảy giai đoạn (AST, HIR, SSA, type inference, effect analysis, reactive analysis, code generation)
  • Compiler giả định component tuân theo Rules of React; vi phạm gây ra silent opt-out, được phát hiện bởi eslint-plugin-react-hooks với preset recommended
  • Tối ưu hóa thủ công vẫn cần thiết cho subscription external store, tính toán nặng với tập dữ liệu lớn, logic imperative dựa trên ref và caching xuyên component
  • Cấu hình thực tế khác nhau theo framework: SWC-native trong Next.js, @rolldown/plugin-babel trong Vite 8, mặc định bật trong Expo SDK 54+
  • Trong phỏng vấn, cần trình bày rõ cả những gì compiler tự động hóa (80-90% memoization) và những gì nó không làm (external state, tính toán nặng xuyên component, class components)
  • Lộ trình áp dụng được khuyến nghị là bật ESLint rules trước, sau đó mới kích hoạt compiler — nhà tuyển dụng thường hỏi về chiến lược áp dụng từng bước này

Bắt đầu luyện tập!

Kiểm tra kiến thức với mô phỏng phỏng vấn và bài kiểm tra kỹ thuật.

Thẻ

#react
#react-compiler
#memoization
#interview
#performance

Chia sẻ

Bài viết liên quan