Tại sao React component của tôi re-render 2 lần?
Bài viết này Được sẽ lý giải một số trường hợp component React của bạn bị re-render 2 lần dù bạn đã kiểm tra kĩ lắm rồi nhưng vẫn không phát hiện lỗi sai.
Trước tiên mình sẽ liệt kê một số lý do làm component React của các bạn bị re-render
🥇 Những trường hợp làm React Component Re-render
-
Cập nhật state mới cho component
-
Thay đổi props component
-
Thay đổi url khi sử dụng router
-
Component cha re-render dẫn đến component con re-render
Đó là những trường hợp phổ biến nhất mà ai cũng đều biết. Chúng ta có thể khắc phục bằng cách dùng useMemo
, useCallback
, hay React.memo
.
Bài viết này mình không đề cấp đến những cái trên mà là việc
-
callback trong
useEffect
chạy 2 lần do dùng React Strict Mode -
Cập nhật state giống state cũ nhưng component vẫn re-render
🥇 Sử dụng React Strict Mode làm component bị mount và unmount
Đây là trường hợp phổ biến và hay gặp nhất, nhiều bạn mới code React không hiểu tại sao lại thêm cái Strict Mode này vào làm gì để cho việc kiểm soát re-render của các bạn bị rối.
Đúng là thoạt nhìn qua thì thấy rối thật, nó làm component của các bạn mount (khởi tạo) rồi lại unmount (hủy)
Dẫn đến code xử lý trong component bị chạy 2 lần (hãy xem đoạn code console.count("Render");
) và callback trong useEffect
bị gọi 2 lần (xem đoạn code console.count("Số lần Callback trong useEffect chạy");
).
Nhìn ví dụ dưới đây
Tất cả lý do trên đều do React Strict Mode gây nên, nếu bạn tắt React Strict Mode thì sẽ không còn gặp hiện tượng đó nữa. Và React Strict Mode chỉ hoạt động ở môi trường dev thôi, khi build ra production thì nó không hoạt động.
🥈 Vậy tác dụng của React Strict Mode là gì?
Như cái tên gọi của nó, đây là "Chế độ an toàn cho React", nó sẽ giả sử các trường hợp có thể xảy ra trong thực tế khi ứng dụng bạn chạy
Ví dụ mình gọi API trong useEffect()
như thế này thì API sẽ bị gọi 2 lần ngay lần đầu app mình chạy
Books.jsx
App.jsx
Ý React Strict Mode muốn nói ở đây là trong thực tế cái API đó có thể bị gọi liên tiếp 2 lần và có thể gây ảnh hưởng đến ứng dụng của bạn.
Lúc này bạn nghĩ "Làm éo gì có chuyện gọi 2 lần API như việc Strict Mode mô phỏng 🤣"
Vậy nếu bây giờ component App
của các bạn như thế này và bạn nhanh tay ấn liên tục button
thì component Books
của bạn sẽ bị mount / unmount liên tục dẫn đến API gọi liên tục.
Và trường hợp có thể xảy ra là khi component Books
bị unmount và sau đó thì api gọi xong, nó tiến hành setBooks(res)
ở một component đã bị hủy 🤣
Đấy! Thực tế điều này vẫn có thể xảy ra.
Vậy khi chúng ta thấy gọi API 2 lần ở useEffect
thì chúng ta nên sử dụng clean up function cho useEffect
Books.jsx
Cancel request bằng AbortController đều có sẵn trên Axios và Fetch API
Nếu các bạn lắng nghe sự kiện trong useEffect
thì cũng nhớ nên hủy việc lắng nghe trong clean up function nhé
Nếu anh em dùng React Query thì nó xử lý giúp chúng ta mấy cái việc lúc nào cũng phải nhớ dùng clean up cho các sự kiện gọi api. Rất tiện luôn. Đó là lý do mình đã chuyển sang dùng React Query.
🥇 Component re-render 2 lần dù setState
cùng giá trị giống nhau
Điều kiện để component của bạn re-render khi dùng setState
là chúng ta phải setState
với giá trị khác với state hiện tại (React sử dụng thuật toán so sánh Object.is())
-
Đối với kiểu dữ liệu nguyên thuỷ thì khác giá trị
-
Đối với object thì khác tham chiếu
Nhưng ta sẽ gặp một trường hợp như dưới đây.
Khi nhấn button lần đầu tiên thì re-render 1 lần (Mary
thành Phạm Hồng Đức
)
Nhấn lần thứ 2 thì re-render lần thứ nữa mặc dù 2 giá trị trước và sau không thay đổi (Phạm Hồng Đức
thành Phạm Hồng Đức
)
Nhấn lần thứ 3 thì không còn thấy hiện tượng re-render nữa.
Các bạn xem demo dưới dây, mình không dùng React Strict Mode trong trường hợp này để các bạn đỡ rối khi nhìn vào console log
Theo như Team React giải thích tại sao component re-render 2 lần dùng setState
cùng giá trị là
-
Khi bạn nhấn
button
ở lần 2, React sẽ không biết liệu bạn có thực sự muốn set state và re-render hay không nên React sẽ re-render. -
Ở lần nhấn
button
thứ 3, khi chúng ta lại set với trị cũ thì bây giờ React sẽ không re-render nữa, vì cả 2 state đều giống nhau.
🥇 Tóm lại
Các bạn thấy đó, mọi chuyện trên đời đều có lý do của nó cả 😁, hy vọng bài viết này có thể giải đáp được các thắc mắc của các bạn bấy lâu nay.
Nguồn bài viết: https://duthanhduoc.com