Truyền Props vào một Component
Các component trong React sử dụng props để giao tiếp với nhau. Mỗi component cha có thể truyền một số thông tin cho các component con của nó bằng cách cung cấp các props. Props có thể khiến bạn liên tưởng đến các thuộc tính trong HTML, nhưng bạn có thể truyền bất kỳ giá trị JavaScript nào thông qua chúng, bao gồm cả đối tượng (objects), mảng (arrays) và hàm (functions).
Bạn sẽ được học
- Làm thế nào để truyền props vào một component
- Làm thế nào để đọc props từ một component
- Làm thế nào để đặt giá trị mặc định cho props
- Làm thế nào để truyền JSX cho một component
- Props thay đổi như thế nào theo thời gian
Những props thường gặp
Props là thông tin mà bạn truyền vào một thẻ JSX. Ví dụ như, className
, src
, alt
, width
, và height
là một vài props mà bạn có thể truyền vào thẻ <img>
:
function Avatar() { return ( <img className="avatar" src="https://i.imgur.com/1bX5QH6.jpg" alt="Lin Lanying" width={100} height={100} /> ); } export default function Profile() { return ( <Avatar /> ); }
Các props mà bạn có thể truyền vào thẻ <img>
đã được định nghĩa sẵn (ReactDOM tuân theo tiêu chuẩn HTML). Nhưng bạn có thể truyền bất kỳ props nào vào component do bạn tự tạo ra, chẳng hạn như <Avatar>
, để tùy chỉnh chúng. Sau đây là cách thực hiện!
Truyền props vào một component
Trong đoạn code này, component Profile
không truyền bất cứ props nào đến component con của nó, Avatar
:
export default function Profile() {
return (
<Avatar />
);
}
Bạn có thể cung cấp vài props cho component Avatar
qua hai bước.
Bước 1: Truyền props đến component con
Đầu tiên, truyền vài props đến component Avatar
. Ví dụ, hãy truyền hai props: person
(một đối tượng - object), và size
(một con số - number):
export default function Profile() {
return (
<Avatar
person={{ name: 'Lin Lanying', imageId: '1bX5QH6' }}
size={100}
/>
);
}
Bây giờ bạn có thể đọc những props này bên trong component Avatar
.
Bước 2: Đọc props trong component con
Bạn có thể đọc các props này bằng cách liệt kê tên của chúng là person, size
cách nhau bằng dấu phẩy, bên trong ({
và })
ngay sau function Avatar
. Cách này cho phép bạn sử dụng chúng bên trong code của Avatar
, giống như bạn sử dụng các biến thông thường.
function Avatar({ person, size }) {
// person và size có sẵn ở đây
}
Thêm một số logic vào Avatar
sử dụng các props person
và size
để hiển thị, và bạn hoàn tất.
Bây giờ bạn có thể cấu hình Avatar
để hiển thị theo nhiều cách khác nhau với các props khác nhau. Hãy thử thay đổi các giá trị nhé!
import { getImageUrl } from './utils.js'; function Avatar({ person, size }) { return ( <img className="avatar" src={getImageUrl(person)} alt={person.name} width={size} height={size} /> ); } export default function Profile() { return ( <div> <Avatar size={100} person={{ name: 'Katsuko Saruhashi', imageId: 'YfeOqp2' }} /> <Avatar size={80} person={{ name: 'Aklilu Lemma', imageId: 'OKS67lh' }} /> <Avatar size={50} person={{ name: 'Lin Lanying', imageId: '1bX5QH6' }} /> </div> ); }
Props giúp bạn suy nghĩ về components cha và con một cách độc lập. Ví dụ, bạn có thể thay đổi các props person
hoặc size
bên trong component Profile
mà không phải suy nghĩ về cách component Avatar
sử dụng chúng. Tương tự, bạn có thể thay đổi cách component Avatar
sử dụng những props này mà không cần phải xem xét về component Profile
.
Bạn có thể nghĩ về props như những “núm điều chỉnh” mà bạn có thể tùy chỉnh. Chúng có vai trò giống như các đối số (arguments) của hàm — thực ra, props chính là đối số duy nhất của component của bạn! Các hàm component React nhận một đối số duy nhất, đó là một đối tượng (object) props
:
function Avatar(props) {
let person = props.person;
let size = props.size;
// ...
}
Thông thường, bạn không cần toàn bộ đối tượng (object) props
, vì vậy bạn sẽ dùng kỹ thuật destructuring để lấy riêng từng prop.
Chỉ định một giá trị mặc định cho một prop
Nếu bạn muốn gán cho một prop một giá trị mặc định để sử dụng khi không có giá trị được chỉ định, bạn có thể làm điều đó bằng cách sử dụng destructuring và đặt dấu =
cùng với giá trị mặc định ngay sau tham số:
function Avatar({ person, size = 100 }) {
// ...
}
Bây giờ, nếu <Avatar person={...} />
được hiển thị mà không có prop size
, thì size
sẽ được gán giá trị là 100
.
Giá trị mặc định chỉ được dùng nếu prop size
bị bỏ qua hoặc nếu bạn truyền size={undefined}
. Nhưng nếu bạn truyền size={null}
hoặc size={0}
thì giá trị mặc định sẽ không được dùng.
Chuyển props bằng cú pháp spread của JSX
Đôi khi, việc truyền props trở nên rất lặp đi lặp lại:
function Profile({ person, size, isSepia, thickBorder }) {
return (
<div className="card">
<Avatar
person={person}
size={size}
isSepia={isSepia}
thickBorder={thickBorder}
/>
</div>
);
}
Việc viết code lặp lại không có gì sai—thậm chí còn giúp dễ đọc hơn. Tuy nhiên, đôi khi bạn có thể ưu tiên sự ngắn gọn. Một số component chuyển tiếp toàn bộ props của chúng đến các component con, giống như Profile
chuyển tiếp cho Avatar
. Vì những component này không sử dụng trực tiếp bất kỳ prop nào, nên việc sử dụng cú pháp “spread” ngắn gọn sẽ hợp lý hơn:
function Profile(props) {
return (
<div className="card">
<Avatar {...props} />
</div>
);
}
Dòng này sẽ chuyển tiếp tất cả các props của Profile
sang Avatar
mà không cần liệt kê từng tên prop một.
Hãy sử dụng cú pháp spread một cách cẩn trọng. Nếu bạn dùng nó trong hầu hết các component, có thể đang có vấn đề trong cách thiết kế. Thường thì điều đó cho thấy bạn nên tách nhỏ các component và truyền nội dung con dưới dạng JSX. Phần tiếp theo sẽ nói rõ hơn về điều này!
Truyền JSX dưới hình thức con (children)
Việc lồng các thẻ trình duyệt có sẵn (built-in browser tags) là điều rất phổ biến:
<div>
<img />
</div>
Đôi khi, bạn cũng sẽ muốn lồng các component do chính bạn tạo ra theo cách tương tự:
<Card>
<Avatar />
</Card>
Khi bạn lồng nội dung bên trong một thẻ JSX, component cha sẽ nhận nội dung đó thông qua một prop có tên là children
. Ví dụ, component Card
dưới đây sẽ nhận prop children
là <Avatar />
và hiển thị nó bên trong một thẻ div bao ngoài:
import Avatar from './Avatar.js'; function Card({ children }) { return ( <div className="card"> {children} </div> ); } export default function Profile() { return ( <Card> <Avatar size={100} person={{ name: 'Katsuko Saruhashi', imageId: 'YfeOqp2' }} /> </Card> ); }
Hãy thử thay thế <Avatar>
bên trong <Card>
bằng một đoạn văn bản để thấy cách component Card
có thể bao bọc bất kỳ nội dung lồng nào. Nó không cần phải “biết” chính xác thứ gì đang được hiển thị bên trong. Bạn sẽ thấy mẫu thiết kế linh hoạt này được sử dụng rất phổ biến ở nhiều nơi.
Bạn có thể hình dung một component có prop children
giống như một “chỗ trống” mà các component cha có thể “lấp đầy” bằng bất kỳ JSX nào. Bạn sẽ thường sử dụng prop children
cho các thành phần bao bọc giao diện, chẳng hạn như: bảng (panel), lưới (grid), v.v.

Illustrated by Rachel Lee Nabors
Props thay đổi như thế nào theo thời gian
Component Clock
dưới đây nhận hai props từ component cha của nó: color
và time
. (Code của component cha được lược bỏ vì nó sử dụng state, phần mà chúng ta chưa đi sâu vào lúc này.)
Hãy thử thay đổi màu trong hộp chọn bên dưới:
export default function Clock({ color, time }) { return ( <h1 style={{ color: color }}> {time} </h1> ); }
Ví dụ này minh họa rằng một component có thể nhận các props khác nhau theo thời gian. Props không phải lúc nào cũng tĩnh! Ở đây, prop time
thay đổi mỗi giây, và prop color
thay đổi khi bạn chọn một màu khác. Props phản ánh dữ liệu của component tại bất kỳ thời điểm nào, chứ không chỉ ở lúc khởi đầu.
Tuy nhiên, props là bất biến (immutable) — một thuật ngữ trong khoa học máy tính có nghĩa là “không thể thay đổi”. Khi một component cần thay đổi props của nó (ví dụ, phản ứng với tương tác người dùng hoặc dữ liệu mới), nó sẽ phải “yêu cầu” component cha truyền cho nó props khác — một đối tượng (object) mới! Các props cũ sẽ bị bỏ qua, và cuối cùng trình thông dịch JavaScript sẽ giải phóng bộ nhớ mà chúng chiếm dụng.
Đừng cố “thay đổi props”. Khi bạn cần phản hồi tương tác của người dùng (chẳng hạn như thay đổi màu được chọn), bạn sẽ cần phải “đặt state” (set state), phần mà bạn có thể tìm hiểu trong State: Một bộ nhớ của Component.
Tóm tắt
- Để truyền props, bạn chỉ cần thêm chúng vào JSX, giống như cách bạn sử dụng các thuộc tính trong HTML.
- Để đọc props, hãy sử dụng cú pháp destructuring
function Avatar({ person, size })
. - Bạn có thể chỉ định giá trị mặc định như
size = 100
, giá trị này sẽ được dùng khi prop bị thiếu hoặc có giá trịundefined
. - Bạn có thể chuyển tiếp tất cả props bằng cú pháp JSX spread
<Avatar {...props} />
, nhưng đừng lạm dụng nó! - JSX lồng nhau như
<Card><Avatar /></Card>
sẽ xuất hiện dưới dạng propchildren
của componentCard
. - Props là các ảnh chụp (snapshot) chỉ đọc theo thời gian: mỗi lần render sẽ nhận một phiên bản mới của props.
- Bạn không thể thay đổi props. Khi bạn cần tương tác với nó, bạn phải sử dụng set state.
Challenge 1 of 3: Tách một component
Component Gallery
này chứa một số đoạn mã rất giống nhau cho hai profile. Hãy tách một component Profile
ra khỏi nó để giảm sự trùng lặp. Bạn sẽ cần quyết định các props nào sẽ truyền cho component đó.
import { getImageUrl } from './utils.js'; export default function Gallery() { return ( <div> <h1>Notable Scientists</h1> <section className="profile"> <h2>Maria Skłodowska-Curie</h2> <img className="avatar" src={getImageUrl('szV5sdG')} alt="Maria Skłodowska-Curie" width={70} height={70} /> <ul> <li> <b>Profession: </b> physicist and chemist </li> <li> <b>Awards: 4 </b> (Nobel Prize in Physics, Nobel Prize in Chemistry, Davy Medal, Matteucci Medal) </li> <li> <b>Discovered: </b> polonium (chemical element) </li> </ul> </section> <section className="profile"> <h2>Katsuko Saruhashi</h2> <img className="avatar" src={getImageUrl('YfeOqp2')} alt="Katsuko Saruhashi" width={70} height={70} /> <ul> <li> <b>Profession: </b> geochemist </li> <li> <b>Awards: 2 </b> (Miyake Prize for geochemistry, Tanaka Prize) </li> <li> <b>Discovered: </b> a method for measuring carbon dioxide in seawater </li> </ul> </section> </div> ); }