Props trong React: Đừng biến Component của bạn thành một cái "thùng rác" trung chuyển!
Lời mở đầu: Cú sốc luồng dữ liệu một chiều (One-Way Data Binding)
Nếu bạn từng code các template engine thời cũ hoặc làm việc với jQuery, bạn quen với việc chọc thẳng vào DOM để nhét dữ liệu vào bất cứ đâu bạn muốn. Nhưng khi bước chân vào React, bạn bị trói buộc bởi một quy tắc sắt đá: Dữ liệu chỉ chảy từ trên xuống dưới (Top-Down).
Và phương tiện duy nhất để dòng chảy đó di chuyển từ Parent Component (Cha) xuống Child Component (Con) chính là Props (viết tắt của Properties).
Nói theo ngôn ngữ của kỹ sư Backend: Component của bạn thực chất chỉ là một cái hàm (Function), và Props chính là Tham số (Arguments) truyền vào cái hàm đó.
1. Bản chất sự Bất biến (Immutability) - Cấm tuyệt đối việc sửa Props!
Đây là cái hố tử thần đầu tiên là nhiều anh em mắc phải.
Trong một số ngôn ngữ (như PHP truyền tham chiếu &, hay C++ dùng con trỏ), bạn có thể thoải mái thay đổi giá trị của tham số truyền vào hàm. Nhưng trong React, Props là Read-Only (Chỉ đọc).
Hãy xem ví dụ "ngây thơ" này:
// ❌ BAD PRACTICE: Cố tình sửa đổi Props
const ProductCard = (props) => {
// Component con cố tình format lại giá tiền từ Props
props.price = props.price * 1000;
return (
<div>
<h2>{props.name}</h2>
<p>Giá: {props.price} VNĐ</p>
</div>
);
}
(Tip: Việc bóc tách cấu trúc - Destructuring { name, price } ngay ở tham số giúp code sạch và rõ ràng hơn rất nhiều so với việc dùng props.name lặp đi lặp lại).
2. Ác mộng kiến trúc mang tên "Prop Drilling"
Khi dự án của bạn scale lên, cây DOM của bạn không chỉ có 2 tầng (Cha - Con), mà nó sâu tới 5, 6 tầng.
Giả sử bạn có dữ liệu userRole nằm ở Component cao nhất (App), nhưng nơi duy nhất cần dùng nó lại là một cái nút Xóa nằm ở tận đáy cùng (DeleteButton).
Thế là bạn phải truyền userRole qua hàng loạt các Component trung gian (Dashboard -> UserList -> UserRow -> ActionPanel -> DeleteButton).
// Cha truyền cho con
const Dashboard = ({ userRole }) => <UserList userRole={userRole} />;
// Con truyền cho cháu
const UserList = ({ userRole }) => <UserRow userRole={userRole} />;
// Cháu truyền cho chắt... (Những thằng ở giữa không hề xài tới dữ liệu này!)
const UserRow = ({ userRole }) => <ActionPanel userRole={userRole} />;
Hậu quả: Những Component ở giữa bỗng dưng bị "ô nhiễm" bởi những Props mà chúng không hề có nhu cầu sử dụng. Bạn vừa biến các Component trung gian thành những "cái thùng rác" trung chuyển. Khả năng tái sử dụng của chúng giảm về con số 0.
3. Lối thoát: Component Composition (Tổ hợp Component)
Làm sao để né Prop Drilling mà chưa cần lôi những "khẩu pháo" nặng nề như Redux hay Context API ra xài?
Câu trả lời nằm ở khái niệm Component Composition thông qua một prop đặc biệt tên là children. Thay vì truyền data đi qua các tầng, hãy truyền nguyên cả cái Component đã ngậm data xuống!
Nhìn cách chúng ta refactor lại kiến trúc:
// Component con bây giờ KHÔNG CẦN biết userRole là gì nữa. Nó chỉ nhận một 'children' và render ra.
const Dashboard = ({ children }) => (
<div className="dashboard-layout">
{/* Render những gì được nhét vào trong nó */}
{children}
</div>
);
// Ở Component cao nhất (App), ta bơm data thẳng vào nơi cần thiết
const App = () => {
const userRole = 'ADMIN';
return (
<Dashboard>
{/* Nhét thẳng DeleteButton vào đây, bỏ qua hàng loạt tầng trung gian! */}
<DeleteButton role={userRole} />
</Dashboard>
);
}
Bằng cách sử dụng children prop, bạn đã thực hiện kỹ thuật Inversion of Control (Đảo ngược quyền điều khiển) ở mức độ UI. Các component con giờ đây hoàn toàn "ngu ngơ" và sạch sẽ, chúng chỉ làm đúng nhiệm vụ là bộ khung layout, còn nội dung bên trong do tầng cao nhất quyết định.
Tóm lại
Hiểu về Props không phải là biết cú pháp props.tên_biến. Hiểu về Props là hiểu về luồng chảy của dữ liệu trong một hệ thống.
- Props là Luồng đi xuống (Top-Down): Cha nói, con nghe.
- Props là Bất biến (Read-only): Cấm tuyệt đối việc sửa đổi dữ liệu gốc từ component con.
- Cảnh giác với Prop Drilling: Đừng biến component thành trạm trung chuyển. Hãy áp dụng
children(Composition) để cấu trúc lại cây DOM một cách thông minh hơn.
Khi nào Props bất lực và bạn cần dữ liệu lan tỏa ra toàn bộ ứng dụng mà không cần truyền tay? Đó là lúc chúng ta bước sang lãnh địa của Global State (Context API / Redux). Hẹn anh em ở bài viết sau!
All rights reserved