⚛️ 揭秘 React 的类型:组件类型
React 的类型系统与 TypeScript 结合使用,为开发者构建类型安全的应用程序提供了一个强大的框架。了解各种 React 类型之间的细微差别,对于做出明智的使用决策至关重要。让我们深入比较这些类型,了解它们之间的区别以及合适的用例。
1️⃣ React.FC 与 React.ElementType
React.FC(React.FunctionComponent)
React.FC
是 React 中专门用于定义函数组件的类型。随着 React Hooks 的引入和广泛采用,它开始变得越来越流行。
在 React 18 之前,它包含一个隐式children
prop,这使得它适合预期有子组件的组件。然而,长期以来,隐式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”)。React.ElementType
当你想接受一个组件作为 prop 并渲染它时,它特别有用,从而允许动态使用组件。
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.ElementType
当你需要动态接受不同类型的 React 组件或 HTML 元素时使用。
2️⃣ React.ReactNode、React.ReactElement 和 JSX.Element 的比较
React.ReactElement
React.ReactElement
是一个由函数创建的对象,具有type
、props
和key
属性React.createElement()
。与 相比,它是一种更具体的类型React.ReactNode
,表示可由 React 直接渲染的元素。
const elementContent: React.ReactElement = <div>Hello, React.ReactElement!</div>;
export const Container = () => <>{elementContent}</>;
React.ReactNode
React.ReactNode
是最具包容性的类型,表示任何可被 React 渲染的内容。这包括原始类型(字符串、数字、布尔值)、JSX.Element
s、React.ReactElement
s、这些类型的数组等等。它是 props 的首选类型,可以接受各种各样的内容,例如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.ReactNode
下面的维恩图描述了和之间的关系React.ReactElement
:
JSX.元素
JSX.Element
本质上是React.ReactElement
一个定义更广的类型,允许各种库以自己的方式实现 JSX。它是 TypeScript 内部使用的类型,用于表示 JSX 表达式的返回类型。
const jsxElement: JSX.Element = <span>Hello, JSX.Element!</span>;
export const Container = () => <>{jsxElement}</>;
比较笔记
React.ReactNode
是最灵活和包容的,适合像小孩子这样可以接受多样化内容的打字道具。React.ReactElement
并且JSX.Element
更加具体,React.ReactElement
适用于 React 创建的元素和JSX.Element
使用 JSX 语法定义的元素。
💡 有趣的事实
- 函数组件的返回值,也就是渲染过程的结果,总是
React.ReactNode
或React.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>
);
}
查看下面的 codesandbox 了解演示:
🏁 结论
了解这些 React 类型和接口之间的差异,可以帮助开发者做出更明智的决策,从而编写更简洁、更易于维护的代码。无论是定义组件、接受动态内容还是处理子元素,选择正确的类型对于充分发挥 React 和 TypeScript 的潜力都至关重要。
如果您想了解如何最佳地组织 React 组件中的代码,请务必查看这篇文章:
请期待我即将发表的文章,深入探讨利用这些类型的理解的模式。
如果您对前端开发和 Web 开发感兴趣,请关注我并查看下面个人资料中我的文章。
文章来源:https://dev.to/itswillt/explaining-reacts-types-940