React 的類型系統與 TypeScript 一起使用時,為開發人員提供了建構類型安全應用程式的強大框架。了解各種 React 類型之間的細微差別對於就其使用做出明智的決策至關重要。讓我們深入詳細比較這些類型,以了解它們的差異和適當的用例。

1️⃣ React.FC 與 React.ElementType

React.FC(React.FunctionComponent)

React.FC是React中專門用來定義函數元件的類型。當 React Hooks 被引入並廣泛採用時,它開始變得更加流行。

在 React 18 之前,它曾經包含一個隱式的children屬性,使其適合預期有孩子的元件。但很長一段時間以來,隱式的children prop類型已經根據React 18的類型變化被刪除了。

這是一個使用範例:

interface SomeComponentProps {
  title: string;
  children?: React.ReactNode;
}

export const SomeComponent: React.FC<SomeComponentProps> = ({ title, children }) => {
  return (
    <article>
      <h2>{title}</h2>

      {children}
    </article>
  );
};

然而,由於刪除了隱children prop 類型,現在使用React.FC的人少了很多,因為與直接將介面分配給 props 物件相比,它很笨重並且沒有提供任何真正的好處:

interface SomeComponentProps {
  title: string;
  children?: React.ReactNode;
}

export const SomeComponent = ({ title, children }: SomeComponentProps) => {
  return (
    <article>
      <h2>{title}</h2>

      {children}
    </article>
  );
};

React.ElementType

另一方面, React.ElementType是一種更廣泛的類型,表示可以由 React 呈現的任何元件類型。這不僅包括 React 函數和類別元件,還包括 HTML 元素的字串標籤(例如「div」、「span」)。當您想要接受元件作為 prop 並渲染它時, React.ElementType特別有用,允許動態元件使用。

const DynamicComponent: React.ElementType = 'div';

export const Container = () => (
  <DynamicComponent className="container">Hello, world!</DynamicComponent>
);

在這裡, DynamicComponent的類型為React.ElementType ,允許它動態分配給不同類型的元件或 HTML 元素。

比較筆記

  • React.FC主要用於定義功能元件。從 React 18 開始,它不再那麼有用了。

  • React.ElementType在接受各種可渲染實體方面提供了更大的靈活性。當您需要可以動態接受不同類型的 React 元件或 HTML 元素的東西時,請使用React.ElementType

2️⃣ React.ReactNode vs React.ReactElement vs JSX.Element

React.ReactElement

React.ReactElement是一個具有typepropskey屬性的物件,由React.createElement()函數建立。與React.ReactNode相比,它是一種更具體的類型,表示可以由 React 直接渲染的元素。

const elementContent: React.ReactElement = <div>Hello, React.ReactElement!</div>;

export const Container = () => <>{elementContent}</>;

React.ReactNode

React.ReactNode是最具包容性的類型,代表任何可以由 React 渲染的東西。這包括原始類型(字串、數字、布林值)、 JSX.ElementReact.ReactElement 、這些類型的陣列等等。這是道具的首選類型,可以接受各種內容,例如children

const multiElementContent: React.ReactNode = (
  <div>
    <p>This is a paragraph.</p>
    {'This is a text node.'}
    {null}
  </div>
);

const primitiveTypeContent: React.ReactNode = "I'm a primitive-type React.ReactNode";

export const Container = () => {
  return (
    <>
      {multiElementContent}
      {primitiveTypeContent}
    </>
  );
};

下面的維恩圖描述了React.ReactNodeReact.ReactElement之間的關係:

React.ReactNode 與 React.ReactElement

JSX.Element

JSX.Element本質上是一個具有更廣泛定義的React.ReactElement ,允許各種程式庫以自己的方式實作 JSX。它是 TypeScript 內部使用的類型,用於表示 JSX 表達式的傳回類型。

const jsxElement: JSX.Element = <span>Hello, JSX.Element!</span>;

export const Container = () => <>{jsxElement}</>;

比較筆記

  • React.ReactNode是最靈活、最具包容性的,適合像孩子一樣可以接受多樣化內容的打字props。

  • React.ReactElementJSX.Element更具體, React.ReactElement適用於 React 建立的元素,而JSX.Element適用於使用 JSX 語法定義的元素。

💡有趣的事實

  • 函數元件的傳回值(也稱為渲染過程的結果)始終是React.ReactNodeReact.ReactElement / JSX.Element 。基本上,函陣列件可以理解為:
type ReactFC<P = {}> = (props: P) => React.ReactNode;
  • 像任何常規函數一樣呼叫函數元件會得到與使用 JSX 語法相同的結果,這意味著:
const MyComponent = ({ children }: { children: React.ReactNode }) => {
  return <div>{children}</div>;
};

export const App = () => {
  return (
    <div>
      <MyComponent>
        Rendering MyComponent with <strong>JSX Syntax</strong>
      </MyComponent>
    </div>
  );
}

是相同的:

const MyComponent = ({ children }: { children: React.ReactNode }) => {
  return <div>{children}</div>;
};

export const App = () => {
  return (
    <div>
      {MyComponent({
        children: (
          <>
            Rendering MyComponent by 
            <strong>Invoking Function Component</strong>
          </>
        ),
      })}
    </div>
  );
}

🏁 結論

了解這些 React 類型和介面之間的差異可以讓開發人員做出更明智的決策,從而產生更乾淨、更易於維護的程式碼。無論您是定義元件、接受動態內容還是處理子元件,選擇正確的類型對於充分發揮 React 和 TypeScript 的潛力至關重要。

請期待我即將發表的文章,這些文章將更深入地探討利用這些類型的理解的模式。


原文出處:https://dev.to/itswillt/explaining-reacts-types-940


共有 0 則留言