头图

总览

当我们把多个子元素传递给一个只期望有一个React子元素的组件时,会产生"React.Children.only expected to receive single React element child"错误。为了解决该错误,将所有元素包装在一个React片段或一个封闭div中。

react-children-only-expected-receive-single-child.png

这里有个示例来展示错误是如何发生的。

// App.js

import React from 'react';

function Button(props) {
  // 👇️ expects single child element
  return React.Children.only(props.children);
}

export default function App() {
  return (
    <Button>
      <button
        onClick={() => {
          console.log('Button clicked');
        }}
      >
        Click
      </button>
      <button
        onClick={() => {
          console.log('Button clicked');
        }}
      >
        Click
      </button>
    </Button>
  );
}

Button元素期望传递单个子元素,但我们在同级下传递了2个子元素。

React片段

我们可以使用React片段来解决该错误。

import React from 'react';

function Button(props) {
  // 👇️ expects single child element
  return React.Children.only(props.children);
}

export default function App() {
  return (
    <Button>
      <>
        <button
          onClick={() => {
            console.log('Button clicked');
          }}
        >
          Click
        </button>
        <button
          onClick={() => {
            console.log('Button clicked');
          }}
        >
          Click
        </button>
      </>
    </Button>
  );
}

当我们需要对子节点列表进行分组,而不需要向DOM添加额外的节点时,就会使用Fragments

你可能还会看到使用了更详细的片段语法。

import React from 'react';

function Button(props) {
  // 👇️ expects single child element
  return React.Children.only(props.children);
}

export default function App() {
  return (
    <Button>
      <React.Fragment>
        <button
          onClick={() => {
            console.log('Button clicked');
          }}
        >
          Click
        </button>
        <button
          onClick={() => {
            console.log('Button clicked');
          }}
        >
          Click
        </button>
      </React.Fragment>
    </Button>
  );
}

上面的两个例子达到了相同的结果--它们对子元素列表进行分组,而没有向DOM中添加额外的节点。

现在大多数代码编辑器都支持更简明的语法,因此更常用。

DOM元素

另一个解决方案是将子元素包裹在另一个DOM元素中,例如一个div

import React from 'react';

function Button(props) {
  // 👇️ expects single child element
  return React.Children.only(props.children);
}

export default function App() {
  return (
    <Button>
      <div>
        <button
          onClick={() => {
            console.log('Button clicked');
          }}
        >
          Click
        </button>
        <button
          onClick={() => {
            console.log('Button clicked');
          }}
        >
          Click
        </button>
      </div>
    </Button>
  );
}

这样就解决了错误,因为我们现在向Button组件传递了单一的子元素。

这种方法只有在添加一个额外的div而不会破坏你的布局时才有效,否则就使用一个片段,因为片段不会向DOM添加任何额外的标记。

这是很有必要的,因为Button组件使用React.Children.only函数来验证children属性是否只有一个子元素,并返回它。否则该方法会抛出一个错误。

React.Children.only方法经常被用于第三方库,以确保API的消费者在使用该组件时只提供一个子元素。


chuck
300 声望41 粉丝