useMemo vs useCallback: 5 Sai Lầm Khiến React App Của Bạn Chậm Đi
Hiểu đúng bản chất của Memoization là nền tảng để bạn tránh những lỗi sai cơ bản và xây dựng codebase sạch, dễ bảo trì hơn. Bài viết này phân tích kỹ lưỡng cách hai hook hoạt động, điểm khác nhau giữa chúng và — quan trọng hơn cả — những tình huống bạn tuyệt đối không nên dùng chúng.

Trung Vũ Hoàng
Tác giả
1. Memoization Trong React Là Gì?
Một điều cần hiểu rõ trước tiên: mọi thao tác trong React đều có chi phí nhất định. Mỗi lần Component re-render, toàn bộ biến và hàm bên trong nó đều được khởi tạo lại từ đầu.
Memoization là kỹ thuật lưu lại kết quả tính toán hoặc định nghĩa hàm vào bộ nhớ đệm. Khi các giá trị đầu vào (dependencies) không đổi, React trả về dữ liệu đã cache thay vì tính toán lại — tiết kiệm tài nguyên CPU.
Tuy nhiên, việc lưu cache đòi hỏi bộ nhớ và thời gian để so sánh dependencies qua từng lần render. Vì vậy, tối ưu hóa quá sớm và thiếu suy nghĩ thường gây hại nhiều hơn lợi.
2. useMemo: Ghi Nhớ Kết Quả Tính Toán
useMemo là hook giúp bạn cache lại giá trị trả về của một hàm — đặc biệt hữu ích khi hàm đó thực hiện các phép tính tốn kém tài nguyên.
Cơ Chế Hoạt Động
Ở lần render đầu tiên, hàm truyền vào useMemo được thực thi bình thường. Từ lần thứ hai trở đi, React kiểm tra mảng dependency:
Nếu dependency thay đổi: Hàm được chạy lại để lấy kết quả mới.
Nếu dependency giữ nguyên: React trả về kết quả đã lưu từ lần render trước — không làm lại bất cứ điều gì.
Ví Dụ Thực Tế
Bạn có danh sách 5.000 sản phẩm và cần lọc theo từ khóa tìm kiếm của người dùng. Đây là phép tính nặng — nhưng chỉ cần tính lại khi danh sách hoặc từ khóa thực sự thay đổi:
const filteredProducts = useMemo(
() => filterLogic(products, query),
[products, query]
);3. useCallback: Ghi Nhớ Định Nghĩa Hàm
Trong khi useMemo cache giá trị, useCallback cache chính cái hàm bạn truyền vào — hàm đó không được thực thi ngay mà chỉ được nhớ lại.
Tại Sao Cần Ghi Nhớ Một Hàm?
Trong JavaScript, hàm là object. Mỗi khi Component re-render, hàm khai báo bên trong nó tạo ra một tham chiếu mới trong bộ nhớ — dù nội dung hàm không hề thay đổi.
Điều này trở thành vấn đề khi bạn truyền hàm đó xuống Component con đã được bọc trong React.memo. Vì hàm mới ≠ hàm cũ (so sánh theo tham chiếu), Component con re-render một cách vô ích.
Khi Nào useCallback Thực Sự Có Giá Trị?
Truyền hàm làm props cho Component con wrapped bởi
React.memo.Hàm là dependency của một Hook khác như
useEffect.
4. Điểm Khác Nhau Then Chốt
Mục đích
useMemo: Cache một giá trị — số, chuỗi, mảng, object...
useCallback: Cache một hàm (function reference).
Giá trị trả về
useMemo: Kết quả sau khi callback được thực thi.
useCallback: Bản thân hàm callback, chưa được thực thi.
Mối liên hệ về cú pháp
Thực ra, useCallback(fn, deps) tương đương hoàn toàn với useMemo(() => fn, deps).
5. Năm Sai Lầm Phổ Biến Khi Dùng Memoization
Thói quen "bọc mọi thứ vào useMemo và useCallback" là một anti-pattern phổ biến. Dưới đây là những lý do thực tế bạn cần dừng lại:
Sai lầm 1: Chi phí so sánh dependency vượt quá lợi ích thu được
Việc so sánh mảng dependency sau mỗi render đôi khi tốn kém hơn cả việc tạo mới một hàm đơn giản. Memoization chỉ có lợi khi hàm thực sự nặng.
Sai lầm 2: Làm code trở nên khó đọc và khó bảo trì
Lạm dụng hook biến Component thành mê cung logic với vô số dependency. Đồng đội vào đọc sẽ không biết phải bắt đầu từ đâu.
Sai lầm 3: Tạo ra Stale Closures — bug khó tìm nhất
Nếu bạn quên thêm một biến vào mảng dependency, hàm sẽ đọc dữ liệu cũ — dẫn đến các bug logic âm thầm mà không có bất kỳ error nào trong console.
Sai lầm 4: Áp dụng với các giá trị nguyên thủy (primitive)
Các kiểu dữ liệu như number, string, boolean luôn được so sánh theo giá trị. Bọc chúng trong useMemo là thừa thãi hoàn toàn.
Sai lầm 5: Tối ưu trước khi đo lường
Đừng thêm Memoization vì "nghĩ là sẽ chậm". Hãy dùng React DevTools Profiler để xác định đúng điểm nghẽn cổ chai trước khi can thiệp.
6. Chiến Lược Tối Ưu Đúng Đắn
Quy trình thực tế tôi áp dụng trong các dự án production:
Bước 1: Viết code tự nhiên, không nghĩ đến tối ưu hóa.
Bước 2: Dùng React DevTools Profiler để tìm Component re-render nhiều nhất.
Bước 3: Kiểm tra xem re-render đó có thực sự gây lag cho người dùng hay không. Nếu không — bỏ qua.
Bước 4: Nếu cần tối ưu, thử tái cấu trúc Component (composition pattern) trước.
Bước 5: Chỉ khi cần thiết — dùng
useMemocho tính toán nặng,useCallbackcho hàm truyền xuống Component con.
7. Tổng Kết
useMemo và useCallback là công cụ mạnh mẽ khi được sử dụng đúng chỗ, nhưng là gánh nặng không cần thiết khi bị lạm dụng. Hãy nhớ:
Dùng
useMemođể bảo vệ kết quả của các phép tính đắt đỏ.Dùng
useCallbackđể duy trì tính nhất quán của tham chiếu hàm khi truyền xuống con.Đo trước, tối ưu sau.
Bạn đã từng gặp trường hợp thêm useMemo vào mà App còn chậm hơn ban đầu chưa? Đó thường là dấu hiệu của sai lầm số 1 hoặc số 3 đã đề cập ở trên!
Bài viết liên quan

Closure Trong JavaScript: Hiểu Tường Tận Để Lập Trình Như Chuyên Gia
Closure — hay còn gọi là "hàm đóng" — là một trong những khái niệm quyền năng và cũng dễ gây bối rối nhất trong JavaScript. Nắm vững Closure không chỉ giúp bạn vượt qua phỏng vấn kỹ thuật cấp Senior mà còn thay đổi cách bạn kiến trúc toàn bộ codebase: gọn hơn, an toàn hơn, và ít bug hơn. Nhiều người hay nhầm lẫn giữa Scope và Closure, nhưng thực ra chúng có quan hệ chặt chẽ và bổ trợ cho nhau. Hãy cùng khám phá từ nền tảng.

useEffect vs useMemo: 5 Khác Biệt Quan Trọng Bạn Cần Hiểu Rõ
Nhầm lẫn giữa useEffect và useMemo là một trong những nguồn gốc phổ biến nhất gây ra các vấn đề hiệu suất trong ứng dụng React. Để dễ hình dung: hãy coi useMemo như một chiếc máy tính bỏ túi biết ghi nhớ kết quả, còn useEffect như một nhân viên trực tổng đài — chờ tín hiệu từ bên ngoài rồi mới hành động.

useMemo vs useCallback: 3 Bí Thuật Tối Ưu React Mà Senior Dev Áp Dụng
Tối ưu hóa hiệu năng trong React thường bị coi là "vùng đất dữ" — nơi nhiều lập trình viên mắc kẹt với những quyết định sai lầm. Việc dùng useMemo và useCallback bừa bãi với hy vọng ứng dụng nhanh hơn đôi khi lại phản tác dụng, bắt CPU phải làm thêm việc so sánh dependencies không cần thiết. Bài viết này giúp bạn dùng hai hook này như một chuyên gia.