Children
Children
允许你处理和转化作为
children
的 JSX。
const mappedChildren = Children.map(children, child =>
<div className="Row">
{child}
</div>
);
Children.count(children)
调用
Children.count(children)
可以获取
children
中的节点数量。
import { Children } from 'react';
function RowList({ children }) {
return (
<>
<h1>行数: {Children.count(children)}</h1>
...
</>
);
}
children
:组件接收到的
children
参数
。
children
中的节点数量。
null
,
undefined
以及布尔值),字符串,数字和
React 元素
都会被统计为一个节点。
在遍历统计的过程中,React 元素不会被渲染,所以其子节点不会被统计
。
Fragment
也不会被统计。对于数组,它本身也不会被统计,但其中的元素遵循上述规则。
Children.forEach(children, fn, thisArg?)
调用
Children.forEach(children, fn, thisArg?)
可以为每个
children
中的每个子节点执行一段代码。
import { Children } from 'react';
function SeparatorList({ children }) {
const result = [];
Children.forEach(children, (child, index) => {
result.push(child);
result.push(<hr key={index} />);
});
// ...
children
:组件接收到的
children
属性
。
fn
:和
数组的
forEach
方法
中的回调类似,是你希望为每个子节点执行的函数。当这个函数执行时,对应的子节点和其下标将分别作为函数的第一、第二个参数,下标从
0
开始自增。
thisArg
:为
fn
函数绑定
this
。默认值为
undefined
。
Children.forEach
返回值是
undefined
。
null
,
undefined
以及布尔值),字符串,数字和
React 元素
都会被统计为单个节点。
在遍历统计的过程中,React 元素不会被渲染,所以其子节点不会被统计
。
Fragment
也不会被统计。对于数组,它本身也不会被统计,但其中的元素遵循上述规则。
Children.map(children, fn, thisArg?)
调用
Children.map(children, fn, thisArg?)
可以对
children
中的每个子节点进行映射或转换。
import { Children } from 'react';
function RowList({ children }) {
return (
<div className="RowList">
{Children.map(children, child =>
<div className="Row">
{child}
</div>
)}
</div>
);
}
children
:组件接收到的
children
属性
。
fn
:和
数组的
map
方法
中的回调类似,是一个映射函数。当这个函数执行时,对应的子节点和其下标将分别作为函数的第一、第二个参数,下标从
0
开始自增。你需要使这个映射函数返回一个 React 节点,它可以是一个空节点(
null
,
undefined
)。
thisArg
:为
fn
函数绑定
this
。默认值为
undefined
。
如果
children
是
null
或者
undefined
,那么就返回这个值。
否则就返回一个由
fn
函数返回节点组成的一维数组。这个数组将包含除
null
和
undefined
以外的所有节点。
空节点(
null
,
undefined
以及布尔值),字符串,数字和
React 元素
都会被统计为单个节点。
在遍历统计的过程中,React 元素不会被渲染,所以其子节点不会被统计
。
Fragment
也不会被统计。对于数组,它本身也不会被统计,但其中的元素遵循上述规则。
如果你在
fn
中返回了一个具有 key 的元素或者元素数组,
各个元素的 key 将自动与其在
children
中对应的原始项的 key 绑定
。当你在
fn
中返回了一个包含了多个元素的数组时,其中的每个元素的 key 都需要保证在这个数组中是独一无二的。
Children.only(children)
调用
Children.only(children)
能够断言
children
代表一个 React 元素。
function Box({ children }) {
const element = Children.only(children);
// ...
children
:组件接收到的
children
属性
。
如果
children
是一个合法的元素
,那么就会返回这个元素。
否则会抛出一个异常。
Children.map
的返回值)作为
children
,那么这个方法会抛出异常。也就是说,这个方法强制要求
children
是一个 React 元素,而不是一个元素数组。
Children.toArray(children)
调用
Children.toArray(children)
能够通过
children
创建一个数组。
import { Children } from 'react';
export default function ReversedList({ children }) {
const result = Children.toArray(children);
result.reverse();
// ...
children
:组件接收到的
children
属性
。
返回一个由
children
中的元素构成的一维数组。
null
,
undefined
以及 布尔值)将在返回的数组中被忽略掉。
返回的元素的 key 将根据原始元素的 key 和其嵌套层级与位置进行计算得到
。这保证了扁平化数组时不会更改原本的行为。
转化 children
如果想修改组件
接收到的
children
属性
,那么可以使用
Children.map
:
import
{ Children } from 'react';
function RowList({ children }) {
return (
<div className="RowList">
{Children.map(children, child =>
<div className="Row">
{child}
</div>
)}
</div>
);
}
在上述例子中,
RowList
用
<div className="Row">
包裹了接收到的每一个子元素。举个例子,假设父组件将三个
<p>
作为
children
属性传递给
RowList
:
<RowList>
<p>这是第一项。</p>
<p>这是第二项。</p>
<p>这是第三项。</p>
</RowList>
然后,使用实现上面的
RowList
,最终的渲染结果将是像下面这样:
<div className="RowList">
<div className="Row">
<p>这是第一项。</p>
</div>
<div className="Row">
<p>这是第二项。</p>
</div>
<div className="Row">
<p>这是第三项。</p>
</div>
</div>
Children.map
和
用来转化数组的
map()
类似
。区别在于
children
被视为
不透明的
。这意味着即使有时它真的是一个数组,你也不应该假设它是一个数组或者其他数据类型。这就是为什么如果你要转换
children
, 应该使用
Children.map
。
import { Children } from 'react'; export default function RowList({ children }) { return ( <div className="RowList"> {Children.map(children, child => <div className="Row"> {child} </div> </div>
深入探讨
在 React 中,
children
属性是被视为 不透明的 数据结构。这意味着你不应该依赖它的结构。如果要转换,过滤,或者统计子节点,你应该使用Children
方法。实际操作过程中,
children
在底层常常被表示为数组。但是如果这里只有一个子节点,那么 React 将不会创建数组,因为这将导致不必要的内存开销。只要你使用Children
方法而不是直接操作children
底层结构,即使 React 改变了children
数据结构的实际实现方式,你的代码也不会被中断。当
children
是一个数组时,Children.map
会有许多有用的特性。比如,Children.map
将被返回元素上的 key 和 你传递给它的children
上的 key 绑定。这保证了原本的 JSX 子元素不会“丢失” key,即使它们上面的例子中那样被包裹。