javascript TypeScript React.FC< Props>混淆

cwdobuhd  于 2023-05-05  发布在  Java
关注(0)|答案(5)|浏览(164)

我正在学习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组件?

o4tp2gmn

o4tp2gmn1#

谢谢大家的回答。他们是正确的,但我正在寻找一个更详细的版本。我做了更多的研究,并在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>
);

与“正常功能”版本的一些区别:
它为displayNamepropTypesdefaultProps等静态属性提供了类型检查和自动完成功能-但是,目前已知将defaultPropsReact.FunctionComponent一起使用时存在问题。详细信息请参阅本期-向下滚动到我们的defaultProps部分,在那里输入建议。
它提供了一个隐式的子类型定义(见下文)-但是隐式子类型存在一些问题(例如:DefinitelyTyped#33006),而且无论如何,明确使用子级的组件可能被认为是一种更好的样式。

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

将来,它可能会自动将props标记为readonly,尽管如果props对象在参数列表中被破坏结构化,那么这一点就没有实际意义了。
React.FunctionComponent是显式的返回类型,而普通函数版本是隐式的(否则需要额外的注解)。
在大多数情况下,使用哪种语法差别很小,但React.FC语法稍微冗长一些,没有明显的优势,因此优先考虑“普通函数”语法。

bzzcjhmw

bzzcjhmw2#

React.FC不是输入React组件的首选方式,这里是link
我个人使用这种类型:

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

React.FC缺点列表:
1.提供子级的隐式定义,即使组件不需要子级。这可能会导致错误。
1.不支持泛型。
1.不能正确使用defaultProps

s4n0splo

s4n0splo3#

最佳方案:

第二种方法+一个返回类型

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

这让你可以完全控制 prop ,而且更明确(没有隐藏的魔法)。
Link to GitHub PR to remove React.FC
Kent C Dodds has some thoughts why this is here

次优方案:

第一个版本(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;
}

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

wqlqzqxt

wqlqzqxt4#

因为你使用的是React和TypeScript,所以你应该总是使用第一种模式,因为它会确保你的组件是更严格的类型,因为它意味着PrintName将是React Functional Component类型,并且它接受Props类型的props。

const PrintName: React.FC<Props>

你可以在React TypeScript类型库中阅读Functional Components的完整接口定义。
您提供的第二个示例没有提供任何形式的类型,除了它是一个接受一组Props类型的参数的函数,并且它可以返回任何一般的东西。
因此,写作

const PrintName2 = (props:Props)

类似于

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

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

oaxa6hgo

oaxa6hgo5#

不要再使用React.FC了。人们过去使用React.FC的原因是因为它在你的 prop 中添加了更多的类型,比如孩子。
在您代码示例中,您不需要子级,因此只需像这样编写

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

但最终会遇到的问题是,您希望将子项传递给组件,而首选的方式如下

interface Props extends React.PropsWithChildren {
   name: string
   priority: "bold" | "normal"
}

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

使用React.PropsWithChildren进行扩展与您输入的内容相同:

interface Props {
   name:string
   priority: "bold" | "normal"
   children?: ReactNode
}

React.PropsWithChildren也可以传递一个泛型,但默认值是未知的。如果你愿意,你可以像这样设置孩子,但是除非你确定你只想要一个特定的类型,否则我只会使用默认值。

React.PropsWithChildren<Button>

并传入组件中所需的子级类型。
您不必传递JSX.Element的返回类型,因为它是推断的。

相关问题