FEMastery
2Level 2 · React Core & Rendering Mechanics

Kiến trúc Core & Cơ chế Render của React

Khám phá sâu bên trong 'hộp đen' của React: từ cách các element được chuyển đổi thành các pixel thực tế trên trình duyệt cho đến cơ chế ngắt quãng render độc đáo và các cạm bẫy thiết kế hệ thống.

Reconciliation algorithmFiber architectureConcurrent renderingTime slicingScheduler prioritiesSuspense boundariesSelective hydrationServer ComponentsTearing in concurrent UIStale closure problem
0%
6 phút đọcThuật toán so khớp cây (Reconciliation)

Reconciliation algorithm

Mỗi lần render, React dựng cây element mới rồi so khớp với cây hiện tại để áp dụng các thay đổi DOM tối thiểu.

Nguyên lý Virtual DOM và Heuristic của Thuật toán So Khớp

Khi xây dựng ứng dụng web, việc thay đổi trực tiếp trên cây DOM thực tế (Real DOM) của trình duyệt là một tác vụ cực kỳ tốn kém hiệu năng và dễ gây ra hiện tượng giật lag (layout thrashing). React giải quyết vấn đề này bằng cách hoạt động trên một bản sao ảo nhẹ hơn gọi là Virtual DOM — một cây cấu trúc đối tượng JavaScript thuần túy mô tả giao diện người dùng.

Trong mỗi lượt render (khi state hoặc props thay đổi), React tạo ra một cây React Element hoàn toàn mới. Thay vì so sánh toàn diện hai cây bằng thuật toán tổng quát có độ phức tạp lý thuyết là O(n³) (không thể áp dụng thực tế), React áp dụng hai giả định heuristics để tối ưu hóa thời gian so khớp xuống còn O(n):

1. Hai phần tử có kiểu dữ liệu (HTML type hoặc Component class/function) khác nhau sẽ tạo ra hai cây hoàn toàn khác nhau.

2. Nhà phát triển có thể cung cấp thuộc tính key ổn định để đánh dấu các phần tử con có thể được tái sử dụng giữa các lần render khác nhau.

VÌ SAOHeuristic same-type/different-type là thứ đưa thuật toán so khớp từ O(n³) lý thuyết - vốn sẽ làm đứng ứng dụng với vài trăm node - về O(n) chạy mượt mà ở 60fps.

Cơ chế So Khớp Chi Tiết và Tầm quan trọng của Key

Khi so khớp hai cây, nếu React thấy hai phần tử ở cùng một vị trí có kiểu khác nhau (ví dụ: đổi từ <div> sang <span>, hoặc <UserProfile> sang <AdminProfile>), React sẽ hủy bỏ (unmount) toàn bộ cây con cũ cùng với state của nó, rồi xây dựng và gắn (mount) cây con mới từ đầu.

If hai phần tử có cùng kiểu, React giữ lại nút DOM thực tế đó, chỉ cập nhật các thuộc tính (attributes, className, style) thay đổi và tiếp tục đệ quy xuống các phần tử con.

Đối với danh sách động, việc sử dụng chỉ số mảng (index) làm key là một lỗi phổ biến. Khi danh sách bị thêm, xóa hoặc sắp xếp lại, các key dạng chỉ số sẽ bị dịch chuyển, khiến React nhận diện sai thực thể DOM cần tái sử dụng. Điều này dẫn tới các lỗi nghiêm trọng như giữ lại dữ liệu cũ trong các ô input, chạy sai hiệu ứng animation, hoặc làm chậm ứng dụng do phải render lại không cần thiết.

tsx
// ĐỪNG DÙNG: index làm key khiến state input bị kẹt ở phần tử DOM cũ
function BadList({ items }: { items: string[] }) {
  return (
    <ul>
      {items.map((item, index) => (
        <li key={index}>
          <span>{item}</span>
          <input type="text" placeholder="Nhập ghi chú..." />
        </li>
      ))}
    </ul>
  );
}

// NÊN DÙNG: key duy nhất ổn định từ data id
function GoodList({ items }: { items: { id: string; name: string }[] }) {
  return (
    <ul>
      {items.map((item) => (
        <li key={item.id}>
          <span>{item.name}</span>
          <input type="text" placeholder="Nhập ghi chú..." />
        </li>
      ))}
    </ul>
  );
}
Tác hại của việc dùng index làm key khi đảo ngược danh sách

KHÔNGĐừng định nghĩa component bên trong hàm render của component khác. Mỗi lần cha render, hàm con sẽ được khởi tạo lại ở một tham chiếu mới, khiến React hiểu đó là loại component khác, lập tức remount toàn bộ nhánh con và làm mất sạch trạng thái (state).

NÊNLuôn dùng ID duy nhất từ database làm key cho các danh sách động. Chỉ dùng index khi danh sách hoàn toàn tĩnh và không bao giờ bị lọc, thêm, xoá hoặc sắp xếp.