TypeScript React.FC<Props> 混淆

IT技术 javascript reactjs typescript frontend react-functional-component
2021-04-12 07:54:01

我正在学习 TypeScript,有些东西让我感到困惑。一位如下:

interface Props {
  name: string;
}

const PrintName: React.FC<Props> = (props) => {
  return (
    <div>
      <p style={{ fontWeight: props.priority ? "bold" : "normal" }}>
        {props.name}
      </p>
    </div>
  )
}

const PrintName2 = (props: Props) => {
  return (
    <div>
      <p style={{ fontWeight: props.priority ? "bold" : "normal" }}>
        {props.name}
      </p>
    </div>
  )
}

对于上面的两个功能组件,我看到 TypeScript 生成了相同的 JS 代码。PrintName2就可读性而言,组件对我来说似乎更加精简。我想知道这两个定义之间有什么区别,是否有人在使用第二种类型的 React 组件?

4个回答

谢谢大家的回答。他们是正确的,但我正在寻找更详细的版本。我做了更多的研究,并在 GitHub上的React+TypeScript Cheatsheets找到了这个

函数组件
这些可以写成普通函数,它们接受一个 props 参数并返回一个 JSX 元素。

type AppProps = { message: string }; /* could also use interface */

const App = ({ message }: AppProps) => <div>{message}</div>;

怎么样React.FC/ React.FunctionComponent您还可以使用React.FunctionComponent(或简写React.FC编写组件

const App: React.FC<{ message: string }> = ({ message }) => (
  <div>{message}</div>
);

与“正常功能”版本的一些区别:

它提供了类型检查和自动完成像静态属性displayNamepropTypes以及defaultProps-但是,也有使用目前已知的问题defaultPropsReact.FunctionComponent有关详细信息,请参阅此问题- 向下滚动到我们的defaultProps部分以在那里输入建议。

它提供了子项的隐式定义(见下文)——但是,隐式子项类型存在一些问题(例如绝对类型#33006),无论如何,对于使用子项的组件进行显式显示可能被认为是更好的风格。

const Title: React.FunctionComponent<{ title: string }> = ({
  children,
  title
}) => <div title={title}>{children}</div>;

将来,它可能会自动将 props 标记为只读,但如果 props 对象在参数列表中被解构,这是一个有争议的问题。

React.FunctionComponent 返回类型是显式的,而普通函数版本是隐式的(否则需要额外的注释)。

在大多数情况下,使用哪种语法几乎没有区别,但是React.FC语法稍微冗长,没有提供明显的优势,因此优先考虑“普通函数”语法。

嘿嘿,详细解释的链接是我第一段提到的github链接。:) 谢谢
2021-06-07 07:54:01
嘿 Kuldeep,首先感谢您的详细回答。也许它缺少“有关详细信息,请参阅此问题”的链接。如果我弄错了请无视:)
2021-06-21 07:54:01

React.FC不是键入 React 组件的首选方式,这里是一个链接

我个人使用这种类型:

const Component1 = ({ prop1, prop2 }): JSX.Element => { /*...*/ }

React.FC缺点的简短列表

  1. 提供子项的隐式定义,即使您的组件不需要有子项。这可能会导致错误。
  2. 不支持泛型。
  3. 不能与defaultProps.
你如何输入 check prop1、prop2 等?
2021-05-29 07:54:01
@ArafatZahan 你可以写{ prop1, prop2 }: { prop1: string, prop2: number }参见stackoverflow.com/questions/53329592/...
2021-06-07 07:54:01
或者 { prop1, prop2 }: Props
2021-06-08 07:54:01
使用React.VFC,如果你不使用“孩子”道具
2021-06-08 07:54:01
@KJSudarshan 很棒的笔记,应该有更多。点赞或回答
2021-06-09 07:54:01

由于您使用的是 React 和 TypeScript,因此您应该始终使用第一种模式,因为它会确保您的组件具有更严格的类型,因为它意味着PrintName将是 React Functional Component 类型,并且它接受 type 的 props Props

const PrintName: React.FC<Props>

您可以在 React TypeScript 类型存储库中阅读 Functional Components 的完整接口定义

您提供的第二个示例不提供任何形式的类型,只是它是一个接受一组 type 参数的函数Props,并且它可以返回任何一般的东西。

因此,写

const PrintName2 = (props:Props)

类似于

const PrintName2: JSX.Element = (props:Props) 

因为 TypeScript 肯定无法自动推断它是一个功能组件。

行。但是应该推断第二种情况下的返回类型。悬停在它上面显示如下: const PrintName2: (props: Props) => JSX.Element
2021-06-01 07:54:01
虽然它会被推断,但有时推断并不完全正确,而且如果在添加返回值之前先添加类型信息,在满足返回类型规范之前,您将收到错误
2021-06-02 07:54:01
最佳答案,直接
2021-06-08 07:54:01
它可能会将其推断为 jsx 元素,但不会自动将其推断为功能组件
2021-06-15 07:54:01

最佳解决方案:

第二种方法+返回类型

const PrintName2 = ({ prop1, prop2 }: Props): JSX.Element => { /** */}

这使您可以完全控制props并且更加明确(没有隐藏的魔法)。

链接到 GitHub PR 以删除 React.FC

Kent C Dodds 有一些想法为什么会在这里

次优解:

第一个版本 (React.FC) 会为你添加一些类型——它们来自React Typings

interface FunctionComponent<P = {}> {
  (props: PropsWithChildren<P>, context?: any): ReactElement | null;
  propTypes?: WeakValidationMap<P>;
  contextTypes?: ValidationMap<any>;
  defaultProps?: Partial<P>;
  displayName?: string;
}

这种方法很有用,有几个原因,但一个明显的原因是如果您的组件有子组件,那么您不需要手动添加childrenprop。这不是很好,因为默认props存在问题并且许多组件没有子级。