TypeScript React.FC<Props> 混乱
TypeScript React.FC<Props> confusion
我正在学习 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 组件?
最佳解决方案:
第二种方法+一种return类型
const PrintName2 = ({ prop1, prop2 }: Props): JSX.Element => { /** */}
这使您可以完全控制道具,并且更加明确(没有隐藏的魔法)。
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
属性。这不是很好,因为默认道具存在问题并且许多组件没有子组件。
由于您使用的是 React 和 TypeScript,因此您应该始终使用第一种模式,因为它将确保您的组件类型更严格,因为它暗示 PrintName
将属于 React 功能组件类型,它接受 Props
.
类型的道具
const PrintName: React.FC<Props>
您可以在 React TypeScript 类型上阅读功能组件的完整接口定义 repository。
你提供的第二个例子没有提供任何形式的类型,除了它是一个函数,它接受一组 Props
类型的参数,并且它可以 return 中的任何东西一般的。
因此,写作
const PrintName2 = (props:Props)
类似于
const PrintName2: JSX.Element = (props:Props)
因为 TypeScript 肯定无法自动推断它是一个功能组件。
感谢大家的回答。它们是正确的,但我一直在寻找更详细的版本。我做了更多研究并在 GitHub 上的 React+TypeScript Cheatsheets 上找到了这个。
函数组件
这些可以写成带有 props 参数和 return JSX 元素的普通函数。
type AppProps = { message: string }; /* could also use interface */
const App = ({ message }: AppProps) => <div>{message}</div>;
React.FC
/React.FunctionComponent
呢?
您还可以使用 React.FunctionComponent
(或 shorthand React.FC
)编写组件:
const App: React.FC<{ message: string }> = ({ message }) => (
<div>{message}</div>
);
与“正常功能”版本的一些差异:
它为 displayName
、propTypes
和 defaultProps
等静态属性提供类型检查和自动完成功能 - 但是,目前已知使用 defaultProps
和 [=14] 存在问题=].有关详细信息,请参阅此 issue - 向下滚动到我们的 defaultProps
部分以在此处输入建议。
它提供了子项的隐式定义(见下文)——但是隐式子项类型存在一些问题(例如 DefinitelyTyped#33006),明确说明使用子项的组件可能被认为是一种更好的样式, 反正.
const Title: React.FunctionComponent<{ title: string }> = ({
children,
title
}) => <div title={title}>{children}</div>;
将来,它可能会自动将 props 标记为只读,但如果 props 对象在参数列表中被解构,那将是一个有争议的问题。
React.FunctionComponent
是关于 return 类型的显式,而普通函数版本是隐式的(否则需要额外的注释)。
In most cases, it makes very little difference which syntax is used,
but the React.FC
syntax is slightly more verbose without providing
clear advantage, so precedence was given to the "normal function"
syntax.
React.FC
不是输入 React 组件的首选方式,这里是 link.
我个人用的是这个类型:
const Component1 = ({ prop1, prop2 }): JSX.Element => { /*...*/ }
React.FC
缺点的简短列表:
- 提供子项的隐式定义,即使您的组件不需要有子项。这可能会导致错误。
- 不支持泛型。
- 无法与
defaultProps
一起正常工作。
我正在学习 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 组件?
最佳解决方案:
第二种方法+一种return类型
const PrintName2 = ({ prop1, prop2 }: Props): JSX.Element => { /** */}
这使您可以完全控制道具,并且更加明确(没有隐藏的魔法)。
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
属性。这不是很好,因为默认道具存在问题并且许多组件没有子组件。
由于您使用的是 React 和 TypeScript,因此您应该始终使用第一种模式,因为它将确保您的组件类型更严格,因为它暗示 PrintName
将属于 React 功能组件类型,它接受 Props
.
const PrintName: React.FC<Props>
您可以在 React TypeScript 类型上阅读功能组件的完整接口定义 repository。
你提供的第二个例子没有提供任何形式的类型,除了它是一个函数,它接受一组 Props
类型的参数,并且它可以 return 中的任何东西一般的。
因此,写作
const PrintName2 = (props:Props)
类似于
const PrintName2: JSX.Element = (props:Props)
因为 TypeScript 肯定无法自动推断它是一个功能组件。
感谢大家的回答。它们是正确的,但我一直在寻找更详细的版本。我做了更多研究并在 GitHub 上的 React+TypeScript Cheatsheets 上找到了这个。
函数组件
这些可以写成带有 props 参数和 return JSX 元素的普通函数。
type AppProps = { message: string }; /* could also use interface */
const App = ({ message }: AppProps) => <div>{message}</div>;
React.FC
/React.FunctionComponent
呢?
您还可以使用 React.FunctionComponent
(或 shorthand React.FC
)编写组件:
const App: React.FC<{ message: string }> = ({ message }) => (
<div>{message}</div>
);
与“正常功能”版本的一些差异:
它为 displayName
、propTypes
和 defaultProps
等静态属性提供类型检查和自动完成功能 - 但是,目前已知使用 defaultProps
和 [=14] 存在问题=].有关详细信息,请参阅此 issue - 向下滚动到我们的 defaultProps
部分以在此处输入建议。
它提供了子项的隐式定义(见下文)——但是隐式子项类型存在一些问题(例如 DefinitelyTyped#33006),明确说明使用子项的组件可能被认为是一种更好的样式, 反正.
const Title: React.FunctionComponent<{ title: string }> = ({
children,
title
}) => <div title={title}>{children}</div>;
将来,它可能会自动将 props 标记为只读,但如果 props 对象在参数列表中被解构,那将是一个有争议的问题。
React.FunctionComponent
是关于 return 类型的显式,而普通函数版本是隐式的(否则需要额外的注释)。
In most cases, it makes very little difference which syntax is used, but the
React.FC
syntax is slightly more verbose without providing clear advantage, so precedence was given to the "normal function" syntax.
React.FC
不是输入 React 组件的首选方式,这里是 link.
我个人用的是这个类型:
const Component1 = ({ prop1, prop2 }): JSX.Element => { /*...*/ }
React.FC
缺点的简短列表:
- 提供子项的隐式定义,即使您的组件不需要有子项。这可能会导致错误。
- 不支持泛型。
- 无法与
defaultProps
一起正常工作。