Function Components
通常情况下,函数式组件可以被定义为接收一个props入参,返回一个JSX元素的普通函数:
type AppProps = { message: string }; /* could also use interface */
const App = ({ message }: AppProps) => <div>{message}</div>;
这里我们需要注意一种场景,函数式组件只能返回JSX表达式( JSX.Element extends ReactElement )和null,因此在有些场景下我们不得不去做一些进行类型强转和断言,保证编译器能够识别:
const MyArrayComponent = () => (Array(5).fill(<div />) as any) as JSX.Element;
React.FC
React中提供了接口类型 React.FC
/React.FunctionComponent
,通过 React.FC 来声明组件,可以显示地定义函数式组件的属性约束:
const App: React.FunctionComponent<{ message: string }> = ({ message }) => (
<div>{message}</div>
);
type FC<P = {}> = FunctionComponent<P>;
interface FunctionComponent<P = {}> {
(props: PropsWithChildren<P>, context?: any): ReactElement | null;
propTypes?: WeakValidationMap<P>;
contextTypes?: ValidationMap<any>;
defaultProps?: Partial<P>;
displayName?: string;
}
PropsWithChildren 规定函数式组件可以接受包括children节点以及组件本身的泛型属性:
type PropsWithChildren<P> = P & { children?: ReactNode };
同时,函数式组件的返回值是ReactElement或null.
Note: React.createElement() 函数的返回值是一个实现了JSX.Element ( ReactElement
) 的对象;而ReactNode 则涵盖了一个组件的多种场景下的返回类型。
Hooks
useRef
当我们使用useRef来创建ref容器时,通常有两种方式:
const ref1 = useRef<HTMLElement>(null!);// 初始值为null,但强行声明使用时不为空
const ref2 = useRef<HTMLElement | null>(null);
ref1.current 是只读的,通常会把ref1交给React内置的ref去维护;而ref2.current是可以修改的,我们可以用它维护自己需要的实例变量。
Custom Hooks
如果我们在自定义Hook中直接返回一个数组,TS的类型推断会把返回类型为Union Type 数组:
export function useLoading() {
const [isLoading, setState] = React.useState(false);
const load = (aPromise: Promise<any>) => {
setState(true);
return aPromise.finally(() => setState(false));
};
return [isLoading, load] infers (boolean | typeof load)[]
}
为了避免错误的类型推断,可以使用TS提供的「const assertions」:
return [isLoading, load] as const; // infers [boolean, typeof load]
当然也可以显式声明为特定类型:
return [isLoading, load] as [
boolean,
(aPromise: Promise<any>) => Promise<any>
];