React cung cấp một API là React.Children. API này hỗ trợ các tiện ích để tương tác với các cấu trúc dữ liệu chưa xác định (opaque data structure). React.Children được xem như một props của component, sử dụng cú pháp là this.props.children hoặc props.children để đại diện cho bất cứ thành phần con nào được truyền vào.
Children trong React.Childen có thể là đối tượng nào?
Children có thể là bất cứ đối tượng nào: React element, component, string, number, object, function…
Thông tin chi tiết React.Children
Child element
Mọi thẻ JSX, hoặc các đoạn text bình thường đều là có thể là một “children”.
Ví dụ:
const Picture = (props) => {
return (
<div>
<img src={props.src}/>
{props.children}
</div>
)
}
Component Picture chứa element <img /> và nhận vào đối tượng props. Như ta thấy props có src và children được gọi để sử dụng.
function App() {
return (
<Picture src="https://wiki.tino.org/wp-content/uploads/2021/09/download.png">
{/* Nhưng gì được đặt trong này đều là props.children */}
<p>This is a cute image</p>
</Picture>
);
}
Thay vì ta sử dụng thẻ đóng <Picture src=”/image-1.jpg” />, thì ta sẽ không có giá trị children của props.
Child Component
Chúng ta có thể lồng các component vào với như tương tự như các thẻ HTML, đó cũng là lý do vì sau cú pháp JSX giống với HTML.
Các component hay nội dung được lồng bên trong component đều là children.
const Avatar = () => {
return <img src="/avatar.jpg" alt="" />;
};
const CommentList = (props) => {
return <div>{props.children}</div>;
};
const Content = () => {
return (
<>
<p>Wiki Tino</p>
<p>5.0 Based on 195 reviews</p>
</>
);
};
function App() {
return (
<div className="commentBox">
<h1>Comments</h1>
<div className="commentBox">
<CommentList>
<Avatar />
<Content />
</CommentList>
</div>
</div>
);
}
Như ta thấy, cặp thẻ component <CommentList><CommentList/> có chứa 2 component con bên trong. Cả hai component này đều là một props.children.
Không những thế, những thuộc tính, event của children đều được hoạt động tốt khi truyền qua props. Ví dụ:
function CardStyle(props) {
return <div style={{ backgroundColor: props.color }}>{props.children}</div>;
}
function Card(props) {
return (
<CardStyle color="#d0d0d0">
<h1>{props.title}</h1>
<p>{props.message}</p>
{props.children}
</CardStyle>
);
}
class SignUpCard extends React.Component {
constructor(props) {
super(props);
this.handleChange = this.handleChange.bind(this);
this.handleSignUp = this.handleSignUp.bind(this);
this.state = { email: "" };
}
render() {
return (
<Card
title="Nhận thông báo bài viết mới"
message="Nhập email để có thể nhận thông báo về bài viết mới: "
>
<input value={this.state.email} onChange={this.handleChange} />
<button onClick={this.handleSignUp}>Đăng ký !</button>
</Card>
);
}
handleChange(e) {
this.setState({ email: e.target.value });
}
handleSignUp() {
alert(`Chúc mừng ${this.state.email} đã đăng ký nhận bài viết mới !`);
}
}
ReactDOM.render(<SignUpCard />, document.getElementById("root"));
Phân tích ví dụ trên, bên trong cặp thẻ component <Card></Card> có 2 React element là <input /> và <button> – đó chính là children. Và element input có sự kiện onChange để bắt dữ liệu nhập vào, element button có sự kiện onClick để alert ra thông tin đã nhập vào từ input, những sự kiện và thuộc tính của các element này được gọi bằng props.children được hoạt động rất bình thường, không gây ra lỗi và giảm hiệu suất.
Tiếp theo là component <CardStyle></CardStyle>. Component nhận element <h1> và <p>, và cả props.children của component <Card> được truyền từ component <SignUpCard>. Bật F12 của trình duyệt lên, ta sẽ thấy các children khác được render bên trong thẻ div của component <CardStyle>. Vì thế, chúng ta có thể sử dụng children lồng bao nhiêu component đều được.
Children với vòng lặp
React cung cấp hai phương thức thường dùng là React.Children.map
và React.Children.forEach
. Cách sử dụng tương tự với map() và forEach() đối với array.
Ví dụ:
function App() {
return (
<CommentList>
<h1>First comment</h1>
<h2>Second comment</h2>
</CommentList>
);
}
ReactDOM.render(<App />, document.getElementById("root"));
Ta thấy, component <CommentList> có children là 2 element <h1> và <h2>, children ở đây là một array chứa hai đối tượng react element, khi log ra ta có thể thấy giá trị của children như sau:
Để render các element cần thiết thì ta sử dụng React.Children.map để duyệt mảng và trả về các element đúng với điều kiện. Ví dụ, chỉ render những element nào là thẻ h1:
function CommentList(props) {
return (
<div>
{React.Children.map(props.children, (child) => {
if (child.type === "h1") return child;
})}
</div>
);
}
hoặc:
function CommentList(props) {
return (
<div>
{props.children.map((child) => {
if (child.type === "h1") return child;
return null;
})}
</div>
);
}
React.Children.forEach cũng tương tự React.Children.map, nhưng nó không trả về một giá trị nào cả.
React.Children.count
Như đã nói ở trên, children có thể là bất cứ giá trị gì, nên việc đếm số lượng children cũng sẽ bị nhầm lẫn.
Ví dụ:
function App() {
return (
<CommentList>
<h1>1st comment</h1>
<h2>2nd comment</h2>
<h1>3rd comment</h1>
<h2>4rd comment</h2>
{() => console.log("testing")}
</CommentList>
);
}
Nếu ta sử dụng {props.children.length}
thì kết quả sẽ trả về là 5, vì children thực tế là một array chứa bất kìa các phần tử nào. Nhưng khi ta sử dụng React.Children.count(props.children)
thì kết quả sẽ trả về là 4, vì hàm này chỉ đến những phần tử nào là React Element.
Vì vậy, tùy vào yêu cầu như thế nào mà ta lựa chọn cách sử dụng cho phù hợp.
React.Children.only
Phương thức này bắt buộc một component chỉ có duy nhất một childrent, ví dụ:
function CommentList(props) {
return <div>{React.Children.only(props.children)}</div>;
}
CommentList.propTypes = {
children: PropTypes.func.isRequired
}
Nếu component <CommentList> có children nhận vào hơn 1 đối tượng:
function App() {
return (
<CommentList>
<h1>1st comment</h1>
<h1>3rd comment</h1>
</CommentList>
);
}
thì React sẽ ném ra lỗi như sau:
React.Children.toArray
Phương thức này dừng để tạo mới một mảng children với các key gắn vào các element con. Nó hữu ích khi muốn sắp xếp, cắt hoặc xử lý các props.children:
class CommentList extends React.Component {
render() {
const children = React.Children.toArray(this.props.children);
return <p>{children.sort()}</p>;
}
}
Hy vọng kiến thứ phía trên sẽ giúp các bạn hiểu rõ hơn về React.Children. Cám ơn các bạn đã ghé thăm bài viết.
Bài viết có tham khảo thông tin từ link: https://reactjs.org/docs/react-api.html#reactchildren