Change detection trong Angular và React

Lâu rồi mình cũng ít có dịp làm việc với React, cũng như dạo gần đây cũng không có cơ hội tiếp xúc nhiều với Angular nên 2 cái framework và library này dường như sắp xa lạ với mình hẳn..

Mình vẫn thích xem React như là 1 thư viện chuyên về render view hơn là 1 framework, anyway thì đó chỉ là nhìn nhận của mình thôi.

TL; NR

Khi làm việc với bất kì 1 thư viện hay framework nào, chúng ta hẵn đều nên dành 1 ít thời gian nghiên cứu về cơ chế hoạt động bên trong, nào là làm sao để React render component ra DOM chỉ dựa vào bản mô tả của Virtual DOM hay cơ chế quản lý dependencies trong Angular hoạt động như thế nào. Khi đó chúng ta sẽ có cái nhìn tổng quan hơn về các thư viện, framework và sẽ dễ dàng hơn để xử lý những lỗi phát sinh trong quá trình sử dụng chúng.

Một trong những vấn đề mà ngay từ lúc đầu mình làm việc với những framework/ library này đó là làm sao khi chúng ta cập nhật giá trị trong model ở controller thì giao diện đuợc cập nhật render với giá trị mới đó? Từ thưở mình còn sử dụng jQuery, mỗi lần mình cập nhật giá trị cho 1 biến nào đó, mình cần phải query lên DOM và cập nhật giá trị mới ở những phần giao diện tương ứng.

Trong phạm vi bài viết này, mình xin chia sẽ những hiểu biết của mình về cơ chế change detector mà React và Angular đang vận hành để hiểu rõ hơn về những khác biệt giữa chúng.

Trong phạm vi bài viết này, mình chỉ muốn giới thiệu sơ về điểm khác biệt giữa cơ chế detect change của Angular và React chứ không nhằm đi quá sâu vào cài đặt chi tiết của chúng.

Change detection là gì?

Change detection là quá trình phát hiện ra những phần giao diện cần phải cập nhật mỗi khi có một giá trị model bên dưới đuợc cập nhật (thông qua tác động từ người dùng hoặc từ network (rest API, …)

Cơ chế hoạt động của CD trong Angular

Angular tiến hành quy trình detect changes mỗi khi có notification. Những notification này đuợc emit mỗi khi có 1 trong những hành động dưới đây diễn ra

  1. Sự kiện phát sinh từ UI (button click, input changes, form submit).
  2. Timing event như setTimeout, setInterval.
  3. Những sự kiện liên quan đến network (như kết quả trả về từ 1 request HTTP).

Để làm đuợc việc đó, Angular cần điều chỉnh những Web API mặc định bằng cách viết lại chúng bằng cách sử dụng thư viện zone.js để chúng có thể phát notification mỗi khi những webAPI này thực hiện xong và gửi yêu cầu tiến hành quy trình detect change về cho hệ thống.

Sau đây là các bước Angular thực hiện:

  1. Khi Angular bắt đầu chạy, nó sẽ note lại list bindings cho những component là những ràng buộc giữa view và model (tức là khi model update thì phần nào trên view cần phải cập nhật lại.). Từ lúc này trở về sau, Angular chỉ quan tâm đến list những bindings này chứ không quan tâm đến tổng thể những phần khác.
    Vì Angular là 1 cây các component, nên ta sẽ có đuợc hình dạng phân cấp như sau:
  2. Khi state của 1 component thay đổi (do các tác động từ 1 trong các yếu tố như đã nêu trên), quá trình change detector sẽ chạy duyệt hết tất cả các component từ đỉnh xuống đáy
    undefined
  3. Ở mỗi compoent, list binding đuợc duyệt và tién hành re-evaluate lại model của chúng.Khi giá trị của model bị thay đổi khác so với giá trị cũ, giao diện tương ứng với model đó sẽ đuợc cập nhật lại. Việc này sẽ thực hiện trên toàn bộ list binding của component hiện hành truớc khi quá trình change detection thực hiện ở các component con.

Lưu ý ở đây là Angular sẽ chỉ update lại phần UI nào liên quan đến model bị thay đổi chứ không render lại toàn bộ UI của component.

Cơ chế hoạt động của CD trong React

React có cơ chế hoạt động tương đối đơn giản hơn. Như chúng ta đã thấy trên thì mỗi khi có những sự kiện bất đồng bộ diễn ra thì Angular sẽ tiến hành quá trình detect changes. Vậy React hoạt động như thế nào nhỉ?

Khi 1 props hoặc state của component thay đổi, hàm render() đuợc gọi. Mỗi khi hàm render đuợc gọi, nó sẽ trả về kết quả là bản mô tả nội dung DOM tree (chứ k phải là DOM tree) – hay còn đuợc gọi là bản mô tả cho virtual DOM với nội dung model mới nhất. Sau đó, quá trình CD bắt đầu. :).

Chi tiết quá trình gồm các bước như sau:

  1. Mỗi khi hàm render đuợc gọi, React sẽ tạo ra virtual DOM dựa trên những gì đuợc mô tả trong kết quả trả về của hàm render().
  2. Sau đó,cây virtual DOM đuợc so sánh với virtual DOM ở lần render trước để tìm ra những điểm trên UI cần cập nhật, Chi tiết về phương pháp tìm DOMDiff bạn có thể check tại https://reactjs.org/docs/reconciliation.html#the-diffing-algorithm
  3. Dựa trên những điểm khác nhau khi so sánh 2 virtual DOM tree ở thời điểm truớc và sau khi update state/props, React sẽ cập nhật lại tương ứng trên DOM thật.

Tóm tắt

Như vậy chúng ta đã luớt sơ qua về cơ chế detect changes của Angular va React, mình có thể tóm tắt những diểm khác nhau chủ yếu thông qua bảng dưới đây:

AngularReact
Trigger CDKhi có sự kiện bất đồng bộ diễn raKhi props or state changed.
Cơ chếDirty checking: So sánh giá trị model và cập nhật lại những UI part tương ứng với modelDOM Diff: Tạo ra virtual DOM và so sánh với virtual DOM cũ đễ tìm ra những thay đổi trên UI cần render lại.
Hiệu suấtAngular mặc định sẽ chạy quá trình detect changes trên toàn bộ dự án từ root node tới bottom.React sẽ không tiến hành chạy detect changes từ root node, mà chỉ bắt đầu từ vị trí mà ở đó component có props hoặc state thay đổi.
Cải thiệnSử dụng onPush hoặc chỉnh sửa lại chiến luợc detect changes mặc định– Sử dụng key attribute cho list những phần tử giống nhau.
– Cực kì hạn chế cập nhật Element tag name.

Give some ideas