React.Children 提供了用于处理 props.children 不透明数据结构的实用方法。
React.Children.map
React.Children.map(children, function[(thisArg)])
在 children 里的每个直接子节点上调用一个函数。如果 children 是一个数组,它将被遍历并为数组中的每个子节点调用该函数。如果子节点为 null 或是 undefined,则此方法将返回 null 或是 undefined,而不会返回数组。
【注意】
如果 children 是一个 Fragment 对象,它将被视为单一子节点的情况处理,而不会被遍历。
React.cloneElement(
element,
[props],
[...children]
)
以 element 元素为样板克隆并返回新的 React 元素。返回元素的 props 是将新的 props 与原始元素的 props 浅层合并后的结果。新的子元素将取代现有的子元素,而来自原始元素的 key 和 ref 将被保留。
React.cloneElement() 几乎等同于:
{children}
但是,这也保留了组件的 ref。这意味着当通过 ref 获取子节点时,你将不会意外地从你祖先节点上窃取它。相同的 ref 将添加到克隆后的新元素中。
下面介绍有趣的玩法。
以下代码,都可以直接复制到codesandbox,查看效果: https://codesandbox.io/s/fe4n6
栅格布局下,如果每个元素是个Card,内容是后端给的,他们的高度不统一,可能出现参差不齐的情况:
import React from 'react';
import ReactDOM from 'react-dom';
import 'antd/dist/antd.css';
import {
Row, Col } from 'antd';
const App = (props) => {
const a = new Array(props.length).fill('A').join(' ');
return (
<div style={
{
background: 'red'}}>
{
a}
</div>
);
};
const data = [20, 30, 40, 50];
ReactDOM.render(
<>
<Row gutter={
24}>
{
data.map((item, index) => (
<Col key={
index} span={
6}>
<App length={
item}/>
</Col>
))}
</Row>
</>,
document.getElementById('container'),
);
当然,你可以利用flex,设置Row
是flex,并设置align-items: stretch;
,并为每个
添加样式height: 100%
。
import React from 'react';
import ReactDOM from 'react-dom';
import 'antd/dist/antd.css';
import {
Row, Col } from 'antd';
const App = (props) => {
const a = new Array(props.length).fill('A').join(' ');
return (
<div style={
{
background: 'red', ...props.style}}>
{
a}
</div>
);
};
const data = [20, 30, 40, 50];
ReactDOM.render(
<>
<Row gutter={
24} style={
{
alignItems: 'stretch'}}>
{
data.map((item, index) => (
<Col key={
index} span={
6}>
<App style={
{
height: '100%'}} length={
item}/>
</Col>
))}
</Row>
</>,
document.getElementById('container'),
);
但是这不方便。
最方便的是封装一下Row和Col。并且在Col中直接给children的所有元素赋style值 height: 100%
。大大减少了开发者心智负担。(开发组件库时很有用,尤其是基于antd等封装自己的业务组件时)
import React from 'react';
import ReactDOM from 'react-dom';
import 'antd/dist/antd.css';
import {
Row, Col } from 'antd';
const MyRow = (props) => {
return (
<Row
{
...props}
style={
{
alignItems: 'stretch', ...props.style }}
/>
);
};
const MyCol = (props) => {
const {
children, ...otherProps } = props;
return (
<Col
{
...otherProps}
>
{
React.Children.map(children, (child) => {
return React.cloneElement(
child,
{
style: {
...child.props.style, height: '100%' }}
);
})}
</Col>
);
};
const App = (props) => {
const a = new Array(props.length).fill('A').join(' ');
return (
<div style={
{
background: 'red', ...props.style}}>
{
a}
</div>
);
};
const data = [20, 30, 40, 50];
ReactDOM.render(
<>
<MyRow gutter={
24} style={
{
alignItems: 'stretch'}}>
{
data.map((item, index) => (
<MyCol key={
index} span={
6}>
<App length={
item}/>
</MyCol>
))}
</MyRow>
</>,
document.getElementById('container'),
);