🔥Được vừa ra mắt khóa học Node.js Super đấy, xem thử đi nào

Tại sao React component của tôi re-render 2 lần?

🎉 Nếu anh em thấy Front-End cạnh tranh quá thì chúng ta học thêm Back-End thôi.

Mình đang có khóa học🏆 Node.js Super, với các kiến thức như: Express.js, TypeScript, MongoDB, Socket.io, Docker, AWS, Swagger, ...

Vậy nên anh em có thể mua ngay từ bây giờ để tăng khả năng pass phỏng vấn nhé 😉

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

jsx
function Books() {
const [books, setBooks] = useState([])
useEffect(() => {
getBooks().then((res) => {
setBooks(res)
})
}, [])
return <div>Books</div>
}

App.jsx

jsx
import Books from './Books'
export default function App() {
return (
<div className="App">
<Books />
</div>
)
}

Ý 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.

jsx
import Books from './Books'
export default function App() {
const [visible, setVisible] = useState(true)
return (
<div className="App">
<button onClick={() => setVisible((prev) => !prev)}>Ẩn hiện Books</button>
{visible && <Books />}
</div>
)
}

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

jsx
function Books() {
const [books, setBooks] = useState([])
useEffect(() => {
getBooks().then((res) => {
setBooks(res)
})
return () => {
// Cancel Request tại đây!
// controller.abort()
}
}, [])
return <div></div>
}

Cancel request bằng AbortController đều có sẵn trên AxiosFetch 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 và khóa học ReactJs Super của mình cũng dạy React Query cho các bạn 💓


🥇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 Dư Thanh Đượ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 (Dư Thanh Được thành Dư Thanh Được)

Nhấn lần thứ 3 thì không còn thấy hiện tượng re-render nữa.

jsx
export default function App() {
const [name, setName] = useState('Mary')
return (
<div>
<button onClick={() => setName('Dư Thanh Được')}>Change Name</button>
<div>{name}</div>
</div>
)
}

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.


Khóa học ReactJs giúp bạn chinh phục mức lương 25 - 30 triệu/tháng

Phew! Cuối cùng bạn cũng đã đọc xong. Bài viết này có hơi dài một tí vì mình muốn nó đầy đủ nhất có thể 😅

Chúng ta đều hiểu rằng Javascript và React không hề dễ, chúng có quá nhiều concept cần phải học. Mình cũng cảm thấy nó khó! Nay lại có thể Typescript nữa 🥲, thật sự khó nuốt.

Nhưng đừng lo: Bạn có thể nắm vững các kiến thức trên chỉ trong một khóa học ReactJs Super - Shopee Clone Typescript

Mình đã bắt đầu code React vào năm 2019, và nó đã trở thành thư viện ưa thích của mình để xây dựng UI và web app. Mình cũng đã làm việc với nhiều framework khác như Angular, Vue nhưng thực sự chỉ có React là đem lại cho mình cảm xúc và sự hiệu quả. 💓

Nếu bạn đang gặp khó khăn với React, mình ở đây để giúp bạn!

Mình đã dành hơn 6 tháng để phát triển khóa học ReactJs Super - Shopee Clone Typescript. Trong khóa này bạn sẽ được học mọi thứ về thư viện ReactJs, các kiến thức từ cơ bản cho đến nâng cao nhất, mục đích của mình là giúp bạn chinh phục mức lương 25 - 30 triêu/tháng

Nếu bạn cảm thấy bài viết này của mình hữu ích, mình nghĩ bạn sẽ thích hợp với phong cách dạy của mình. Không như bài viết này, khóa học là sự kết hợp giữa các bài viết, video, quizz, bài tập nhỏ và dự án lớn có thể xin việc được ngay. Học xong mình đảm bảo bạn sẽ lên tay ngay. 💪🏻

Avatar Dư Thanh Được
Dư Thanh Được
Một developer thích nghiên cứu và chia sẻ kiến thức về lập trình, blockchain, marketing. Chuyên code và dạy lập trình website