React.Children.map的用法
React.Children用很多用法,如下图,经常会用到的是toArray()
,具体用法可以自行了解,这里记录下map()
的用法和使用到的场景。
1. 用法:React.Children.map接收2个参数,第一个是所有子元素,第二个是个回调,可以对每个子元素进行处理,然后返回处理后的子元素。
2. 使用场景:子元素(也可理解为子组件)有相同的处理逻辑或者数据(脑里突然闪出useContext和useReducer,可以尝试看看);子元素是不确定的,无法使用传统的父子组件(准确说,这里的子元素是个页面,有七八个页面需要增加相同的业务需求,这个做法有点类似网站的顶部导航这类公共布局,因此第一个想法就是定义一个
Layout
,使用React.Children.toArray
,然后在需要处理的页面上最外层加上<Layout>...</Layout>
,但是这样没法对子元素页面进行操作,所以采用React.Children.map
来实现子元素页面想要的功能(这里用到React.cloneElement
)。脑里又闪出新的想法,将这七八个页面路由入口都放在Layout
上,通过路径决定子元素使用哪个页面组件,这样就是传统的父子组件传递数据,或许更容易理解)。3. 实现代码:
// Layout.tsx
interface LayoutProps {
children: React.ReactElement | React.ReactElement[];
}
function Layout(props: LayoutProps) {
const location = useLocation();
const pathname = location.pathname;
const sessionKey = `Filter_${pathname}`;
// 获取缓存的数据
const searchStr = sessionStorage.getItem(sessionKey);
// 即用即销
sessionStorage.removeItem(sessionKey);
// 这里想要实现,点击前往其他页面前,将本页面的搜索条件缓存,便于下次回到本页面时使用
const handleClick = (searchVal: SearchValProps, id: string) => {
if (searchVal && Object.keys(searchVal).length > 0) {
const searchStr = JSON.stringify(searchVal);
sessionStorage.setItem(sessionKey, searchStr);
}
window.location.href = linkUrl(jobId);
};
return (
<div className="template-layout">
{React.Children.map(props.children, (child: React.ReactElement) =>
// cloneElement第二个参数将作为child的props传入
React.cloneElement(child, {
searchVal: searchStr ? JSON.parse(searchStr) : undefined,
onClickJobCard: handleClick,
})
)}
</div>
);
}
export default Layout;
// Page1.tsx
function Index(props: any) {
const {
searchVal,
onClickJobCard,
...otherProps
} = props;
const [filterVals, setFilterVals] = useState<any>({});
useEffect(() => {
setFilterVals(searchVal);
}, [searchVal]);
const handleClick = (jobId: string, prefix: string) => {
onClickJobCard(filterVals, jobId, prefix);
};
return (
<div>
// 这里简单写了,意思到位即可
<Search value={filterVals} ... />
<Card onClick={handleClick} ... />
</div>
}
function Page1(props: any) {
// 这里的props是原来的props,如果想在原子组件Index中使用,需要作为属性再次传入
return (
<JobLayout>
<Index {...props} />
</JobLayout>
);
}
export default Page1;