Re-render là gì trong React
Khi nói đến performance của React, chúng ta có 2 trạng thái cần quan tâm:
- render lần đầu - khi component xuất hiện lần đầu trên màn hình
- re-render - render lại một component đã xuất hiện trên màn hình Thường thì re-render xảy ra khi user tương tác với ứng dụng gây ra sự thay đổi dữ liệu, state của ứng dụng và component cần được render lại để hiển thị tương ứng với dữ liệu mới. Tuy nhiên không phải re-render nào cũng cần thiết, có thể chia ra làm 2 loại re-render
- Loại cần thiết - component có sử dụng dữ liệu đã thay đổi. Ví dụ như input cần re-render khi user nhập dữ liệu
- Loại không cần thiết - bị re-render do ảnh hưởng từ những component khác, không thay đổi gì sau khi re-render. Re-render không phải lúc nào cũng gây ra vấn đề gì to tác, cơ bản React rất nhanh, việc re-render xảy ra gần như người dùng không thể để ý được, chỉ với những component thật sự phức tạp, mỗi lần render tiêu tốn nhiều thời gian, lúc này chúng ta dễ thấy hiện tượng lag, giao diện delay trên mỗi lần render.
Tại sao lại re-render
Có thể gom lại 4 nguyên nhân tại sao component re-render: state thay đổi, component cha/con re-render, context thay đổi, hook thay đổi.
Do state thay đổi
Do parent re-render
Component sẽ bị render nếu component parent re-render, hay nói đúng hơn, một component mà re-render, đám child của nó cũng re-render, mặc dù cũng có một vài trường hợp cá biệt, component child có thể trigger render component parent
Do context thay đổi
Một giá trị bên trong context thay đổi, toàn bộ component nằm trong context đó sẽ re-render, dù là nó không sử dụng giá trị bị thay đổi. Có thể chặn re-render này bằng cách memoization, sẽ được đề cập bên dưới.
Do hook
Nếu bên trong hook có thay đổi, component sẽ re-render, và re-render này là không thể chặn được.
Phương pháp hạn chế re-render
Một anti pattern (khuyến cáo không nên dùng) là tạo component bên trong hàm render của component
Cách viết bên trái trên mỗi lần re-render, nó sẽ re-mount lại <SlowComponent />
, nó sẽ xóa component, khởi tạo một component hoàn toàn mới mỗi lần re-render <Component />
Đóng gói
Hãy phân tích lợi ích của cách viết bên phải, chúng ta gom state và các component liên quan đến state này vào một component, khi giá trị state open
thay đổi, so với cách viết bên trái, component <VereSlowComponent />
sẽ không bị ảnh hưởng
Sử dụng prop children
Hơi giống như cách ở trên, chúng ta tách state vào một component độc lập, nhưng vì ở đây <VereSlowComponent />
phải nằm bên trong, chúng ta dùng prop children
, như thế dù <ComponentWithScroll />
có re-render, vẫn không ảnh hưởng đến <VerySlowComponent />
Đây cũng là một trường hợp cá biệt cho thấy không phải parent render thì child component sẽ render
Truyền prop là component
Cũng tương tự như children
nếu chúng ta truyền component như một prop, nó sẽ không bị re-render dù cho component chính render
Dùng API của React
Nếu không đủ tinh tế và muốn xài đồ có sẵn cho an toàn thì chúng ta đã có sẵn API của react React.memo
, useMemo
Sử dụng useMemo
, useCallback
cũng cần nhắc không hẳn dùng mọi lúc, mọi nơi sẽ tối ưu, đôi khi nó lại ngốn ram của user, và trong một số trường hợp nó không có tác dụng, như trường hợp sau
Một gợi ý là nếu thấy các prop không phải kiểu primitive value thì có thể cân nhắc memorize
Initializing...