在 React + TypeScript 开发中,理解以下核心类型对编写类型安全的组件非常重要。以下是常见 React 类型的详细解释:
1. ReactElement
ReactElement
表示一个 React 元素,它是 React 应用中最基本的构建块。一个 React 元素可以是一个 HTML 标签(如 <div>
、<p>
等)或者是一个自定义组件。表示虚拟 DOM 的基本单元,通常由 JSX 转换而来
用例:
import React from 'react';
const element: ReactElement = <div>Hello, World!</div>;
2. ReactNode
ReactNode
是一个更宽泛的类型,它可以表示任何可以在 JSX 中渲染的内容。这包括 ReactElement
、字符串、数字、数组、null
undefined
和 boolean
等。
type ReactNode =
| ReactChild
| ReactFragment
| ReactPortal
| boolean
| null
| undefined;
用例:
function Container({ children }: { children: React.ReactNode }) {
return <div>{children}</div>;
}
import React, { ReactNode } from 'react';
function renderContent(content: ReactNode) {
return <div>{content}</div>;
}
renderContent(<p>Paragraph</p>); // ReactElement
renderContent('Hello'); // 字符串
renderContent(123); // 数字
renderContent([<span>Item 1</span>, <span>Item 2</span>]); // 数组
renderContent(null); // null
renderContent(false); // boolean
3. JSX.Element
与 ReactElement 类似,但更严格地表示 JSX 表达式的结果
declare namespace JSX {
interface Element extends React.ReactElement {}
}
4. ReactChild
ReactChild
是 ReactNode
的子集,它只包括 ReactElement
、字符串和数字。
import React, { ReactChild } from 'react';
function renderChild(child: ReactChild) {
return <div>{child}</div>;
}
renderChild(<p>Paragraph</p>); // ReactElement
renderChild('Hello'); // 字符串
renderChild(123); // 数字
5. ReactFragment
ReactFragment
表示一个 React 片段,它允许你在不添加额外 DOM 节点的情况下将多个子元素组合在一起。ReactFragment
可以是一个空标签 <></>
或者 <React.Fragment></React.Fragment>
。
import React, { ReactFragment } from 'react';
const fragment: ReactFragment = (
<>
<p>First</p>
<p>Second</p>
</>
6. React.ComponentType
表示类组件或函数组件的类型,React.ComponentType
表示一个 React 组件类型,它可以是一个函数组件或类组件。
type ComponentType<P = {}> = ComponentClass<P> | FunctionComponent<P>;
用例(HOC):
function withLogger<T>(WrappedComponent: React.ComponentType<T>) {
return (props: T) => {
console.log('Rendered!');
return <WrappedComponent {...props} />;
};
}
7. FunctionComponent (FC)
React.ComponentType
表示一个 React 组件类型,它可以是一个函数组件或类组件。
推荐写法:
const MyComponent: React.FC<MyProps> = ({ title }) => {
return <div>{title}</div>;
};
8. PropsWithChildren
自动包含 children 属性的 props 类型助手,ReactPropsWithChildren
它用于为组件的 props 类型添加 children
属性。组件需要显式读取 children 时,方便定义。
用例:
import React, { ReactPropsWithChildren } from 'react';
interface MyComponentProps extends ReactPropsWithChildren {
title: string;
}
function MyComponent({ title, children }: MyComponentProps) {
return (
<div>
<h1>{title}</h1>
{children}
</div>
);
}
9. React.ReactElement vs JSX.Element vs ReactNode
类型 | 包含内容 | 典型使用场景 |
---|---|---|
ReactElement | JSX 创建的单个元素 | createElement 返回值 |
JSX.Element | 同 ReactElement,但类型更严格 | 函数组件返回值类型 |
ReactNode | 所有可渲染内容 | 组件 children 类型定义 |
10. 合成事件类型
常见事件处理类型:
React.ChangeEvent<HTMLInputElement> // 输入框变更
React.MouseEvent<HTMLButtonElement> // 鼠标事件
React.KeyboardEvent<HTMLInputElement> // 键盘事件
React.FormEvent<HTMLFormElement> // 表单提交
用例:
const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
console.log(e.target.value);
};
11. Ref 相关类型
React.RefObject<T> // useRef 创建的不可变 ref 对象
React.MutableRefObject<T> // 可变 ref(需指定泛型参数)
React.LegacyRef<T> // 兼容旧版 ref 类型
用例:
const inputRef = useRef<HTMLInputElement>(null);
12. Context 类型
React.Context<T> // 上下文对象类型
React.ProviderProps<ContextType> // Provider 属性类型
React.ConsumerProps<ContextType> // Consumer 属性类型
用例:
interface ThemeContextType {
color: string;
toggle: () => void;
}
const ThemeContext = React.createContext<ThemeContextType | null>(null);
最佳实践建议:
- 优先使用
ReactNode
作为 children 类型 - 避免过度使用
FC
,推荐显式声明 props 类型 - 事件处理函数优先使用合成事件类型
- 使用
ComponentProps
提取组件 props 类型:
type ButtonProps = React.ComponentProps<typeof Button>;
预祝:代码写的爽,面试答的棒各位~