網站搜尋

reactjs - 如何在 TypeScript 中使用帶有 React 無狀態函數組件的 children


使用 TypeScript 與 React,我們不再需要擴展 React.Props,以便編譯器知道所有 React 組件的 props 都可以有 children:

interface MyProps { }

class MyComponent extends React.Component<MyProps, {}> {
  public render(): JSX.Element {
    return <div>{this.props.children}</div>;
  }
}

然而,對於無狀態函數式組件似乎並非如此:

const MyStatelessComponent = (props: MyProps) => {
  return (
    <div>{props.children}</div>
  );
};

產生編譯錯誤:

錯誤:(102, 17) TS2339: 屬性 'children' 在類型 'MyProps' 上不存在。

我猜這是因為編譯器真的無法知道一個純函數會在 props 參數中接收到 children。

所以問題是我們應該如何在 TypeScript 的無狀態函數組件中使用 children?

我可以回到舊的方式,MyProps 擴展 React.Props,但 Props 介面被標記為棄用,且無狀態元件據我了解既沒有也沒有支援 Props.ref。

所以我可以手動定義 children 屬性:

interface MyProps {
  children?: React.ReactNode;
}

首先:ReactNode是正確的類型嗎?

第二:我必須將 children 寫成可選的(?),否則使用者會認為 children 應該是組件的一個 屬性(<MyStatelessComponent children={} />),如果沒有提供值就會報錯。

看起來我好像漏掉了什麼。有人能解釋一下我的最後一個例子是否是使用帶有 children 的無狀態函數型組件在 React 中使用的正確方式嗎?

答案#1

你可以對你的 props 使用 React.PropsWithChildren<P> 類型:

interface MyProps { }

function MyComponent(props: React.PropsWithChildren<MyProps>) {
  return <div>{props.children}</div>;
}

答案#2

React 16.8 更新:自 React 16.8 起,React.SFC 與 React.StatelessComponent 名稱已不再被棄用。事實上,它們已成為 React.FunctionComponent 類型或簡稱 React.FC 的別名。

不過你會以相同的方式使用它們:

const MyStatelessComponent : React.FunctionComponent<MyProps> = props =>
    <div>
        <p>{props.propInMyProps}</p>
        <p>{props.children}</p>
    </div>

在 React 16.8 之前(舊版):

目前,你可以使用 React.StatelessComponent<> 類型,如下所示:

const MyStatelessComponent : React.StatelessComponent<{}> = props =>
    <div>{props.children}</div>

我在那裡添加的是將組件的返回類型設置為 React.StatelessComponent 類型。

對於具有您自定義屬性(如 MyProps 介面)的組件:

const MyStatelessComponent : React.StatelessComponent<MyProps> = props =>
    <div>
        <p>{props.propInMyProps}</p>
        <p>{props.children}</p>
    </div>

現在,props 不僅擁有 MyProps 介面中的屬性,還有 children 屬性。

我在 TypeScript 版本 2.0.7 中檢查了這個

此外,你可以使用 React.SFC 來代替 React.StatelessComponent,以簡化寫法。

答案#3

更簡單的答案:使用 ReactNode:

interface MyProps {
  children?: React.ReactNode
}

是否 children 是可選的(即是否有 ?)取決於你的元件。? 是表達這點最簡潔的方式,所以這樣做沒問題。

關於歷史:當最初被問到時,這不一定是正確答案:ReactNode 類型幾乎以目前的形式在 2017 年 3 月由這個拉取請求添加,但今天幾乎所有讀這篇文章的人都應該使用足夠現代的 React 版本。

最後,關於將 children 當作「屬性」傳遞(在 React 語境中,這應該是傳遞為「prop」而不是屬性):這是可行的,但在大多數情況下,傳遞 JSX children 會比較易讀:

<MyComponent>
  <p>This is part of the children.</p>
</MyComponent>

比……更容易閱讀

<MyComponent children={<p>This is part of the children.</p>} />