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.

useEffectuseMemoso sánhkhác biệthook Reactside effect
Ảnh bìa bài viết: useEffect vs useMemo: 5 Khác Biệt Quan Trọng Bạn Cần Hiểu Rõ
Ảnh đại diện của Trung Vũ Hoàng

Trung Vũ Hoàng

Tác giả

28/3/20264 phút đọc

1. Bản Chất Cốt Lõi Của Từng Hook

useMemo được sinh ra để giải quyết bài toán Memoization — lưu giữ kết quả của một phép tính tốn kém và chỉ tính toán lại khi các dependency thực sự thay đổi. Mục tiêu duy nhất của nó là ngăn các phép tính nặng chạy lại vô ích sau mỗi lần Component re-render.

useEffect thì ngược lại — đây là nơi xử lý Side Effects: những tác vụ nằm ngoài phạm vi hiển thị của Component như gọi API, thiết lập subscription, hay tương tác trực tiếp với DOM. Nếu bạn nhét logic tính toán vào useEffect, React buộc phải render thêm một lần nữa để cập nhật trạng thái — lãng phí hoàn toàn.

2. Thời Điểm Thực Thi: Khác Biệt Sống Còn

useMemo chạy ngay trong quá trình render (Rendering phase). Khi React đọc code Component để chuẩn bị xuất UI, nó kiểm tra dependency array của useMemo — nếu không thay đổi, giá trị cũ được trả về ngay lập tức. Vì vậy, tuyệt đối không được đưa side effect vào bên trong useMemo, điều đó sẽ làm chậm quá trình hiển thị.

useEffect chỉ chạy sau khi render hoàn tất và trình duyệt đã vẽ xong UI (Commit phase). Thiết kế này đảm bảo các tác vụ nặng như fetch data không block người dùng nhìn thấy giao diện — đây là chủ tâm của React để giữ ứng dụng luôn phản hồi nhanh.

3. Khi Nào Nên Dùng useMemo?

Chỉ nên dùng useMemo trong hai tình huống rõ ràng:

  • Phép tính nặng: Lọc danh sách hàng ngàn phần tử, chạy thuật toán tìm kiếm phức tạp, xử lý dữ liệu lớn...

  • Đảm bảo tính nhất quán tham chiếu: Khi bạn trả về Object hoặc Array và truyền xuống Component con wrapped bởi React.memo. Nếu không có useMemo, Object mới được tạo sau mỗi render — Component con coi đó là "dữ liệu mới" và re-render vô ích.

Đừng dùng useMemo cho phép tính đơn giản — chi phí khởi tạo hook và so sánh dependency có thể còn lớn hơn lợi ích mang lại.

4. Ứng Dụng Thực Tế Của useEffect

useEffect là trạm điều khiển cho mọi thứ diễn ra bên ngoài Component. Các tình huống phổ biến nhất:

  • Gọi API khi Component mount hoặc khi dependency thay đổi.

  • Đăng ký (subscribe) WebSocket để nhận dữ liệu thời gian thực.

  • Thiết lập và dọn dẹp Event Listener.

Một điểm mà useMemo hoàn toàn không có: hàm cleanup. Khi Component unmount hoặc trước khi effect chạy lại, hàm cleanup cho phép bạn hủy yêu cầu API đang dở, xóa listener, giải phóng bộ nhớ — tránh memory leak.

Mẹo nhỏ: Trước khi dùng useEffect để cập nhật state, hãy tự hỏi: "Có thể tính toán giá trị này trực tiếp trong render không?" Nếu có — hãy dùng useMemo hoặc tính thẳng trong thân hàm. Không cần useEffect.

5. Tổng Hợp 5 Khác Biệt Then Chốt

Khác biệt 1: Mục đích

  • useMemo → Ghi nhớ giá trị ("nhớ cái gì đó").

  • useEffect → Xử lý side effect ("làm gì đó").

Khác biệt 2: Thời điểm chạy

  • useMemo → Trong quá trình render (Before Paint).

  • useEffect → Sau khi render hoàn tất (After Paint).

Khác biệt 3: Giá trị trả về

  • useMemo → Một giá trị cụ thể (số, chuỗi, mảng, object...).

  • useEffect → undefined hoặc một hàm cleanup.

Khác biệt 4: Hỗ trợ cleanup

  • useMemo → Không có.

  • useEffect → Có hàm cleanup khi unmount hoặc dependency thay đổi.

Khác biệt 5: Ảnh hưởng đến render

  • useMemo → Tránh render thừa bằng cách giữ nguyên giá trị.

  • useEffect → Có thể kích hoạt thêm render nếu cập nhật state bên trong.

6. Những Sai Lầm Cần Tránh

Stale Closures: Dùng biến bên trong hook nhưng quên khai báo trong dependency array. Code đọc dữ liệu cũ mà không có bất kỳ cảnh báo nào — loại bug âm thầm khó tìm nhất.

Xử lý event trong useEffect: Khi người dùng click "Mua hàng", xử lý logic ngay trong onClick — đừng thay đổi state trung gian rồi chờ useEffect "bắt" lấy. Cách trực tiếp luôn rõ ràng và dễ debug hơn.

Một useEffect làm quá nhiều việc: Tuân thủ nguyên tắc Single Responsibility — mỗi useEffect chỉ đảm nhận một nhiệm vụ. Điều này giúp React quản lý re-render chính xác hơn và giúp đồng đội đọc code dễ hơn.

Tổng Kết

Điều tốt nhất bạn có thể làm là giữ Component đơn giản nhất có thể. Viết code đúng chức năng trước — rồi mới đo lường bằng công cụ profiler để quyết định có cần Memoize hay không. Đừng tối ưu hóa vội vàng dựa trên cảm tính.

Câu hỏi thường gặp

Chia sẻ bài viết
Zalo

Bạn thấy bài viết hữu ích?

Liên hệ với chúng tôi để được tư vấn miễn phí về dịch vụ

Liên hệ ngay

Bài viết liên quan

Ảnh bìa bài viết: Zustand Async: 5 Cách Xử Lý Bất Đồng Bộ Hiệu Quả Trong React
Frontend

Zustand Async: 5 Cách Xử Lý Bất Đồng Bộ Hiệu Quả Trong React

Mọi ứng dụng React thực tế đều phải giao tiếp với API bất đồng bộ. Nếu quản lý kém, ứng dụng dễ rơi vào các vấn đề như UI bị đơ, race condition, rò rỉ bộ nhớ, hay hiển thị dữ liệu cũ. Zustand giải quyết bài toán này với một cú pháp cực kỳ đơn giản — định nghĩa async actions trực tiếp trong store, không cần middleware phức tạp như Redux Thunk hay Saga.

9/5/2026
Ảnh bìa bài viết: Promise Nâng Cao: all, allSettled, race, any — Khi Nào Dùng Cái Nào?
Frontend

Promise Nâng Cao: all, allSettled, race, any — Khi Nào Dùng Cái Nào?

Nếu bạn chỉ dùng async/await tuần tự, ứng dụng của bạn đang bỏ phí tiềm năng hiệu suất — mỗi request phải chờ request trước xong mới bắt đầu. Các phương thức tĩnh của Promise (all, allSettled, race, any) cho phép bạn điều phối nhiều tác vụ bất đồng bộ song song theo chiến lược phù hợp từng bài toán.

9/5/2026
Ảnh bìa bài viết: Zustand Async: 5 Cách Xử Lý Bất Đồng Bộ Hiệu Quả Trong React
Frontend

Zustand Async: 5 Cách Xử Lý Bất Đồng Bộ Hiệu Quả Trong React

Mọi ứng dụng React thực tế đều phải giao tiếp với API bất đồng bộ. Nếu quản lý kém, ứng dụng dễ rơi vào các vấn đề như UI bị đơ, race condition, rò rỉ bộ nhớ, hay hiển thị dữ liệu cũ. Zustand giải quyết bài toán này với một cú pháp cực kỳ đơn giản — định nghĩa async actions trực tiếp trong store, không cần middleware phức tạp như Redux Thunk hay Saga.

1/4/2026