添加链接
link管理
链接快照平台
  • 输入网页链接,自动生成快照
  • 标签化管理网页链接

Children

陷阱

使用 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>
    
    深入探讨

    为什么 children 属性并不总是一个数组?

    在 React 中,children 属性是被视为 不透明的 数据结构。这意味着你不应该依赖它的结构。如果要转换,过滤,或者统计子节点,你应该使用 Children 方法。

    实际操作过程中,children 在底层常常被表示为数组。但是如果这里只有一个子节点,那么 React 将不会创建数组,因为这将导致不必要的内存开销。只要你使用 Children 方法而不是直接操作 children 底层结构,即使 React 改变了 children 数据结构的实际实现方式,你的代码也不会被中断。

    children 是一个数组时,Children.map 会有许多有用的特性。比如,Children.map 将被返回元素上的 key 和 你传递给它的 children 上的 key 绑定。这保证了原本的 JSX 子元素不会“丢失” key,即使它们上面的例子中那样被包裹。

    陷阱

    children 的数据结构中 不会包括你传递的 JSX 组件的渲染输出结果。在下面的例子中,RowList 接收到的 children 仅包含两个子项而不是三个:

    1. <p>这是第一项。</p>
    2. <MoreRows />

    这就是为什么在这个例子中仅产生了两个行级元素容器。

    import RowList from './RowList.js';
    export default function App(
    
    
    
    
        
    ) {
      return (
        <RowList>
          <p>这是第一项。</p>
          <MoreRows />
        </RowList>
    function MoreRows() {
      return (
          <p>这是第二项。</p>
          <p>这是第三项。</p>