
Trong thế giới React, hầu hết các nhà phát triển không cần suy nghĩ nhiều trước khi sử dụng closure trong phương thức render thành phần của họ, đặc biệt là khi ánh xạ qua danh sách.
Nhưng nếu tôi nói với bạn rằng có một giải pháp thay thế mạnh mẽ nhưng chưa được sử dụng nhiều có thể giúp cải thiện hiệu suất, khả năng đọc và thậm chí tích hợp tốt hơn với các công cụ thì sao?
Chúng ta hãy nói về thuộc tính HTML data-* : một tính năng hiếm khi được các nhà phát triển giao diện sử dụng nhưng đáng để xem xét lại.
❓ Thuộc tính data-* là gì?
Thuộc tính HTML data-*cho phép bạn nhúng dữ liệu tùy chỉnh vào các phần tử DOM . Trong HTML thuần túy:
<div data-user-id="123" data-role="admin">John</div>
Trong React , bạn có thể sử dụng chúng theo cùng một cách:
<div data-user-id={user.id} data-role={user.role}>
{user.name}
</div>
Chúng có thể truy cập được trong trình xử lý sự kiện thông qua đối tượng tập dữ liệu:
e.currentTarget.dataset.userId;
🧠 Mẫu phổ biến: Closures trong .map()
Giả sử bạn đang hiển thị danh sách các mục:
{items.map((item) => (
<button key={item.id} onClick={() => handleClick(item.id)}>
{item.name}
</button>
))}
Cách này hiệu quả. Nó dễ đọc và dễ viết.
Nhưng đằng sau hậu trường, bạn đang tạo một hàm mới cho mỗi mục trên mỗi lần kết xuất : một closure nắm bắt item.id.
Trong nhiều ứng dụng, điều này không có tác động thực tế. Tuy nhiên…
⚠️ Những Hạn Chế của Closures
Mặc dù closure là một phần cơ bản của JavaScript và React, nhưng việc sử dụng chúng bên trong .map()có thể có những nhược điểm:
1. Kết xuất lại không cần thiết
Nếu bạn đang sử dụng React.memo, React.useCallback, hoặc danh sách ảo hóa (như react-window ), các tham chiếu hàm mới có thể gây ra việc render lại không mong muốn . Vì hàm được tạo lại mỗi lần, việc ghi nhớ không giúp ích gì.
2. Khó tối ưu hóa hơn
Hãy tưởng tượng bạn đang xây dựng một danh sách có tính tương tác cao, hiển thị hàng trăm mục. Việc giảm thiểu việc hiển thị lại trở nên quan trọng, và các closure nội tuyến có thể gây bất lợi cho việc này .
✅ Giải pháp thay thế:data-*
Thay vì tạo một closure cho mỗi mục, hãy đính kèm siêu dữ liệu trực tiếp vào DOM bằng cách sử dụng data-*:
function handleClick(e) {
const id = e.currentTarget.dataset.id;
console.log("Clicked item:", id);
}
{items.map((item) => (
<button key={item.id} data-id={item.id} onClick={handleClick}>
{item.name}
</button>
))}
🤔 Vậy tại sao không phải ai cũng làm điều này?
Vì closures dễ sử dụng, trực quan và đủ hiệu suất cho hầu hết các ứng dụng, data-*nên có vẻ hơi “cổ điển” và hiếm khi được đề cập trong các hướng dẫn React/Frontend hiện đại.
Nhưng trong những tình huống mà hiệu suất hoặc ghi nhớ là quan trọng, cách tiếp cận này có thể là một viên ngọc ẩn .
✨ Tóm tắt
Mặc dù data-*các thuộc tính không phải là công cụ phổ biến trong bộ công cụ của nhà phát triển React, nhưng chúng mang lại những lợi thế thực sự trong các tình huống cụ thể:
Giảm thiểu việc tạo ra các chức năng không cần thiết
Cải thiện hiệu suất ghi nhớ và kết xuất
Cho phép xử lý sự kiện đơn giản và sạch hơn
Chúng không phải là sự thay thế cho lệnh đóng, nhưng là giải pháp thay thế tuyệt vời khi hiệu suất hoặc kiến trúc yêu cầu.
Bạn đã từng sử dụng data-*các thuộc tính như thế này chưa? Hay bạn thường dùng closure? Tôi rất muốn nghe suy nghĩ và kinh nghiệm của bạn !
Tôi hy vọng bạn thấy bài viết này thú vị. Hãy cho tôi biết suy nghĩ của bạn trong phần bình luận nhé 👇
Nguồn: dev.to