跳到主要内容

为什么React.FC被弃用了

来自github:merged pull request(Remove React.FC from Typescript template)

总结如下React.FC总共有几个缺点:

1.隐式地提供了一个children属性

const App: React.FC = () => { /*... */ };
const Example = () => {
<App><div>Unwanted children</div></App>
}

以上例子不会报错,在App组件定义成React.FC的时候,就包含了children属性。即使你的本意是没有为App提供children属性,但是在Example组件中显然不会报错。

2.不支持泛型

通常我们可以像定义函数的泛型一样定义React的函数式组件,比如常用的Table组件

type GenericComponentProps<T> = {
datasSource: T
column: ColumnProps<T>
}
const GenericComponent = <T>(props: GenericComponentProps<T>) => {/*...*/}

但是使用React.FC的时候无能为力了

const GenericComponent: React.FC</* ??? */> = <T>(props: GenericComponentProps<T>) => {/*...*/}

3. 使组件作为命名空间的类型定义更困难

如下的例子

<Select>
<Select.Item />
</Select>

React.FC中定义SelectSelect.Items的属性通常需要

const  Select: React.FC<SelectProps> & { Item: React.FC<ItemProps> } = (props) => {/* ... */ }
Select.Item = (props) => { /*...*/ }

而是用自己的类型定义仅仅只需要

const Select = (props: SelectProps) => {/* ... */}
Select.Item = (props: ItemProps) => { /*...*/ }

4.不能正确的为defaultProps工作

当我们不使用React.FC时,这样是可以正确的编译的。

type  ComponentProps = { name: string; }

const Component = ({ name }: ComponentProps) => (<div>
{name.toUpperCase()} /* Safe since name is required */
</div>);
Component.defaultProps = { name: "John" };

const Example = () => (<Component />)

但如果使用React.FC则会有问题:如果是使用React.FC<name: string>将会使name变成必传属性,

或者使用React.FC<name?: string>则会使name.toUpperCase()报一个类型错误。

* React.FC的好处

不过React.FC也不是一无是处,他定义了一个返回的类型约束

const Component = () => {
return undefined; // 当这样返回类型时使用React.FC能快速捕捉错误
}

但是这并不能节省多少的工作量:

const Component1 = (props: ComponentProps): JSX.Element => { /*...*/ }
const Component2: FC<ComponentProps> = (props) => { /*...*/ }