Skip to content

React.Children API

React.Children 提供了处理 this.props.children 这个不透明数据结构的工具。

map

React.Children.map 用于对 this.props.children 的每个子级进行遍历。

语法:

jsx
React.Children.map(children, function[(child, index)])

说明:

  1. 如果 children 是个内嵌的对象或者数组,他会被遍历,不会将对象或者数组传入到 function 中。
  2. 如果 children 参数是 null 或者 undefined ,那么返回 null 或者 undefined 而不是一个空对象。
  3. 对数组进行扁平化处理,扁平化的过程中会忽略 null 或者 undefined,如果 children
tsx
<>
    {
        [<span>1</span>,
         <span>2</span>,
         <span>3</span>,
        [<span>4</span>, <span>5</span>],null,undefined];
    }
</>

那么传入 functionchild 就是

tsx
[
  <span>1</span>,
  <span>2</span>,
  <span>3</span>,
  <span>4</span>,
  <span>5</span>,
];

this.props.children 的值有三种可能:

  • 如果当前组件没有子节点,它就是 undefined
  • 如果有一个子节点,数据类型是 object
  • 如果有多个子节点,数据类型就是 array

其他方式

除了使用 React.Child.map 遍历, 还可以使用数组的 map 方法,但是使用数组方法操控 children 有 3 个问题:

  • 用数组的方法需要声明 childrenReactNode[] 类型,这样就必须传入多个元素才行,而 React.Children 不用
  • 用数组的方法不会对 children 做拍平,而 React.Children
  • 用数组的 sort() 方法不能做排序,因为 children 的元素是只读的,而用 React.Children.toArray 转成数组就可以了

当然,不用记这些区别,只要操作 children,就用 React.Children 的 api 就行了。

toArray

React.Children.toArray 可将 this.props.children 转换为数组,在这过程中,会扁平化所有嵌套数组,为每个子元素分配 key

语法:

jsx
React.Children.toArray(children);

代码示例:

tsx
class Sort extends React.Component {
  render() {
    const children = React.Children.toArray(this.props.children);
    return <p>{children.sort().join(" ")}</p>;
  }
}
tsx
<Sort>
  {"bananas"}
  {"oranges"}
  {"apples"}
</Sort>

forEach

语法:

tsx
React.Children.forEach(children, function[(child, index)])

说明:

  1. 遍历 children
  2. 对每个子元素执行某些操作,但不改变或返回新的数据结构

例如:

  • 打印日志
  • 修改 DOM
  • 触发事件
  • 更新组件状态

示例:

jsx
React.Children.forEach(children, (child) => {
  console.log(child.props); // 打印每个子元素的props
  someExternalFunction(child); // 调用外部函数
  if (child.type === "input") {
    inputRefs.current.push(child); // 收集特定类型的子元素引用
  }
});

这里,我们遍历了 children,但没有创建新的数组或修改 children 本身。我们只是使用了每个 child 来执行一些"副作用"操作。

相比之下,Children.map会创建并返回一个新数组,通常用于转换 children

count

React.Children.count 用于计算 this.props.children 中含有的节点数目。

由于 this.props.children 可以是任何类型的,因此检查一个组件有多少个 children 是非常困难的。

如果通过 this.props.children.length 判断字符串或函数时程序便会中断。

语法:

tsx
React.Children.count(children);

only

React.Children.only 限制 this.props.children 只能为单个 React 组件,否则将抛出错误。

语法:

tsx
React.Children.only(children);

最佳实践

改变属性

即便通过以前方法可以在子组件内部获得 this.props.children 以及其每个成员,但是要在子组件中改造 this.props.children(例如添加 Props 属性等)则需要使用辅助方法 React.cloneElement

React.cloneElement 会克隆一个 React 元素,第一个参数为将要克隆的 React 元素,第二个参数则为想要为该克隆元素添加的属性。

tsx
renderChildren(){
    return React.Children.map(this.props.children, (child, index) => {
        return React.cloneElement(child, {
            name: this.props.name,
            number: this.state.number,
            onChange: this.onChange,
        })
    })
}

Crafted with care.