Typescript:与React functional component中接受道具的混淆
浅谈React的React.FC与React.Component的使用
一、定义时 props的类型已知
将类型添加到函数参数
interface TodoListItemProps {
todo: {
text:string
complete:boolean
const TodoListItem = ({ todo }: TodoListItemProps) => {
console.log(todo)
return (
// ...
将类型作为泛型参数添加到FC类型
interface TodoListItemProps {
todo: {
text:string
complete:boolean
const TodoListItem: React.FC<TodoListItemProps> = ({ todo }) => {
return(
// ...
1、将类型添加到函数参数
interface IProps {
name: string
const App = (props: IProps) => {
const {name} = props;
return (
<div className="App">
<h2>{name}</h2>
</div>
export default App;
2、将类型作为泛型参数添加到FC类型
使用React.FunctionComponent<P={}>来定义,也可以使用其简写React.FC<P={}>。
它是在ts中使用的一个泛型接口,可以接收一个参数,参数表示props的类型,这个参数不是必须的。
使用React.FC来写 React 组件的时候,是不能用 setState(在类组件中使用)的,取而代之的是useState()、useEffect等 Hook API。
interface IProps {
name: string
const App: React.FC<IProps> = (props) => {
//解构出 name 的值
const {name} = props;
return (
<div className="App">
<h2>{name}</h2>
</div>
export default App;
const App: React.FunctionComponent<{ message: string }> = ({ message }) => (
console.log('message:', message)
return (
<div>{message}</div>
检查react类型,可以看到:
type React.FC<P = {}> = React.FunctionComponent<P>
interface FunctionComponent<P = {}> {
(props: PropsWithChildren<P>, context?: any): ReactElement<any, any> | null;
propTypes?: WeakValidationMap<P>;
contextTypes?: ValidationMap<any>;
defaultProps?: Partial<P>;
displayName?: string;
与第一种普通的函数声明方法相比:
1、React.FC 对静态属性:displayName,propTypes 和 defaultProps 提供了类型检查和自动补全(注意:defaultProps与React.FC结合使用会存在一些问题)。
2、React.FC 显式地定义了返回类型,其他方式是隐式推导的。
3、React.FC 为 children 提供了隐式的类型(ReactElement | null)。
4、当使用这种形式来定义函数组件时,props中默认会带有children属性,它表示该组件在调用时,其内部的元素。举例如下:
App.tsx
import Child1 from "./child1";
import Child2 from "./child2";
interface IProps {
name: string;
const App: React.FC<IProps> = (props) => {
//其他组件使用App组件,从其传入的 props里,解构出 name的值
const { name } = props;
return (
//将 name的值传给子组件
<Child1 name={name}>
<Child2 name={name} />
TypeScript
</Child1>
export default App;
Child1.tsx
在Child1组件中打印了children属性,它的值是一个数组,包含Child2对象和后面的文本:
interface IProps {
name: string;
const Child1: React.FC<IProps> = (props) => {
const { name, children } = props;
console.log(children);
return (
<div className="App">
<h2>{name}</h2>
</div>
export default Child1;
二、定义时 props的类型未知
如果在定义组件时不知道props的类型,由使用该组件时传入的参数决定,所以只有使用时才知道props的类型,那么定义组件时 就用泛型来定义props的类型。
1、用function定义的函数组件
MyComponent.tsx
// 定义组件
function MyComponent<P>(props: P) {
return (
<span>{props}</span>
page.tsx
// 在使用组件时定义参数类型
type IProps = { name: string; age: number; };
<MyComponent<IProps> name="React" age={18} />; // Success
<MyComponent<IProps> name="TypeScript" age="hello" />; // Error
2、用箭头函数定义的函数组件
必须使用extends关键字来定义泛型参数,才能被成功解析:
const MyComponent = <P extends any>(props: P) => {
return (
<span>{props}</span>
直接调用会报错:
const MyComponent = <P>(props: P) => {
return (
<span>{props}</span>
复制代码