持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第2天,点击查看活动详情
前言
在React中,组件接收到的props.children有多种类型:undefined、object、array。 通常情况下,我们基本不需要对props.children做特殊处理,但在某些情况下,比如将children的每个子元素包装在另一个元素/组件中,或者重新排序或切片它们。这种情况下,就需要用到React给我们提供的工具方法 React.Children。
以下是基本用法:
function Parent({ children }) {
return <div className="mt-10">{children}</div>;
}
如果需要对children进行加强(一个常见的用例是将迭代索引相关信息传递给父组件的子组件):
import { Children, cloneElement } from "react";
function Breadcrumbs({ children }) {
const arrayChildren = Children.toArray(children);
return (
<ul
style={{
listStyle: "none",
display: "flex",
}}
>
{Children.map(arrayChildren, (child, index) => {
const isLast = index === arrayChildren.length - 1;
if (! isLast && ! child.props.link ) {
throw new Error(
`BreadcrumbItem child no. ${index + 1}
should be passed a 'link' prop`
)
}
return (
<>
{child.props.link ? (
<a
href={child.props.link}
style={{
display: "inline-block",
textDecoration: "none",
}}
>
<div style={{ marginRight: "5px" }}>
{cloneElement(child, {
isLast,
})}
</div>
</a>
) : (
<div style={{ marginRight: "5px" }}>
{cloneElement(child, {
isLast,
})}
</div>
)}
{!isLast && (
<div style={{ marginRight: "5px" }}>
>
</div>
)}
</>
);
})}
</ul>
);
}
function BreadcrumbItem({ isLast, children }) {
return (
<li
style={{
color: isLast ? "black" : "blue",
}}
>
{children}
</li>
);
}
export default function App() {
return (
<Breadcrumbs>
<BreadcrumbItem
link="https://goibibo.com/"
>
Goibibo
</BreadcrumbItem>
<BreadcrumbItem
link="https://goibibo.com/hotels/"
>
Hotels
</BreadcrumbItem>
<BreadcrumbItem>
A Fancy Hotel Name
</BreadcrumbItem>
</Breadcrumbs>
);
}
说明:
-
使用
React.Children.toArray确保children是一个数组。因为组件接收到的children属性可能是对象、数组,甚至是一个函数,如果在代码里我们直接使用children.map方法,就会报错。 -
在
Breadcrumbs父组件中,我们使用实用方法遍历它的子组件React.Children.map -
通过访问
index迭代器函数内部(回调函数的第二个参数React.Children.map),检测持否是最后一个子节点 -
如果是最后一个子节点,就克隆元素并将
isLast属性传递给它,以便子元素可以根据它设置自己的样式。 -
如果不是最后一个子节点,我们确保所有不是最后一个孩子的孩子都有一个
link道具,如果他们没有就抛出一个错误。我们像第 4 步一样克隆元素,并isLast像之前一样传递 prop,但我们还额外将这个克隆的元素包装在锚标记中。