React報錯之React.Children.only expected to receive single React element child

chuckQu發表於2022-12-21

總覽

當我們把多個子元素傳遞給一個只期望有一個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的消費者在使用該元件時只提供一個子元素。

相關文章