React props.children
React props.children
React 的特性,或者说 JS 的特性都太抽象勒。
无法理解
在看 React 文档的时候,以我当时的水平,看到了这个令人费解的东西:
function AlertButton({ message, children }) {
return (
<button onClick={() => alert(message)}>
{children}
</button>
);
}
export default function Toolbar() {
return (
<div>
<AlertButton message="正在播放!">
播放电影
</AlertButton>
<AlertButton message="正在上传!">
上传图片
</AlertButton>
</div>
);
}
按我当时的理解,Button 组件中将接收的 props 中的 children 属性作为按钮显示的文本,但这里的 AlertButton 组件没有传递 children 属性,因此按钮应该不显示内容才对。
但实际情况是,按钮不仅正常显示了:

而且当修改 AlertButton 组件的内容,即“播放电影”和“上传图片”时,页面按钮的文本也会改变:
export default function Toolbar() {
return (
<div>
<AlertButton message="正在播放!">
播放电影:すずめの戸締まり
</AlertButton>
<AlertButton message="正在上传!">
上传图片
</AlertButton>
</div>
);
}
页面内容正常变化了:

这就给我整晕了,说明 AlertButton 组件的文本被当成 {children} 了,无法理解。
逐渐理解
拷问了 GPT 和百度了一下后,发现原因了:
props.children 是一个特殊的参数,它表示组件所有的子节点。 它是一个特殊的参数,是隐式传递的。在组件内部通过 props.children 就可以获得组件的子节点,有以下几种情况:
- 组件没有子节点,
props.children类型为 undefined; - 组件有一个子节点,
props.children类型为 object; - 组件有多个子节点,
props.children类型为 array。
但是使用 props.children 参数,要求组件标签必须有开始和结束标签,以标识子节点,之前都没有注意到:
function Toolbar() {
return (
<div>
// 有开始和结束标签
<AlertButton message="正在播放!">
播放电影:すずめの戸締まり
</AlertButton>
<AlertButton message="正在上传!">
上传图片
</AlertButton>
</div>
);
}
在之前(一般情况)都是直接使用自闭合标签传递 props 的,如:
function Toolbar() {
return (
<div>
// 自闭合,列出 props
<AlertButton message="正在播放!" children="播放电影:すずめの戸締まり" />
<AlertButton message="正在上传!">
上传图片
</AlertButton>
</div>
);
}
代码改成这样和之前效果是一样的,但这里就出现了个新问题,直接在 props 中传递 children,但又有子节点,则何如?
function Toolbar() {
return (
<div>
<AlertButton message="正在播放!" children="播放电影:すずめの戸締まり" />
// 既有子节点,又传递了 children props
<AlertButton message="正在上传!" children="上传图片:すずめの戸締まり" >
上传图片
</AlertButton>
</div>
);
}
如此执行了一下,第二个按钮显示的文本还是“上传图片”,看来有子节点的话,children 还是会取子节点;当把子节点删掉时,children 取的就是 props 里传递的值了。
理解一切
除了传递参数以外,children 还有一些其他用法和辅助方法。
插槽
children 可以当成 Vue 里的插槽使用,如
function Child(props) {
return (
<div>
<div>{props.children[2]}</div>
<div>{props.children[1]}</div>
<div>{props.children[0]}</div>
</div>
)
}
function Parent() {
return (
<Child>
<div>这是0,应该排第一</div>
<div>这是1,应该排第二</div>
<div>这是2,应该排第三</div>
</Child>
)
}
Parent 控件中传入子节点的顺序是 0、1、2,但 Child 控件中使用 children 获取到的是一个数组,所以可以按任意顺序读取,实际效果:

这就相当于作为插槽使用了。
React.Children
React 还提供了一些关于 children 的方法,这里简单列一下把:
-
React.Children.map
object React.Children.map(object children, function fn)此方法可以遍历
children里的所有子节点,并在每个子节点中调用 fn 函数,返回一个新的children对象; -
React.Children.forEach
React.Children.forEach(object children, function fn)也是遍历
children里的所有子节点,并在每个子节点中调用 fn 函数,但不返回对象; -
React.Children.count
number React.Children.count(object children)统计
children中的子节点个数,返回个数; -
React.Children.Only
object React.Children.only(object children)检查
children中是否只有一个子节点,返回这个节点,如果有多个子节点则抛出异常。

浙公网安备 33010602011771号