Ick*_*day 7 typescript reactjs
我在任何地方都没有找到任何相关信息,但我对最佳实践感到好奇。
在我的工作项目中,我目前定义我的 props 接口如下:
export interface ExampleComponentProps {
readonly firstExampleProp: string;
readonly secondExampleProp: number
}
Run Code Online (Sandbox Code Playgroud)
export-ing 接口或-ing 成员是否会readonly在编译或运行时产生性能开销?除了可读性和明确性之外,这样做还有什么好处吗?
export-ing props 是一个很好的实践,因为它允许更高级的用例,例如将组件包装在另一个组件中。请参阅下面的示例。readonly到每一个属性我觉得更多的是个人喜好。是的,道具不应该在组件内被覆盖,但同时这是很常见的知识,readonly到处添加可能有点多余。import { ExampleComponent, ExampleComponentProps } from "./ExampleComponent";
type WrappedExampleComponentProps = {
newProperty: string;
} & ExampleComponentProps;
// I wouldn't be able to this if I weren't able to import ExampleComponentProps
export const WrappedExampleComponent = (props: WrappedExampleComponentProps ) => {
const { newProperty, ...otherProps } = props;
return (
<ExampleComponent {...otherProps } />
<SideComponent newProperty={newProperty} />
);
};
Run Code Online (Sandbox Code Playgroud)
就性能而言:运行时绝对不会影响性能,因为运行时不存在任何 TypeScript 构造。在编译时,我想说这些更改对性能的影响可以忽略不计,并且被其优点(例如可扩展性)所抵消。
太长了;是的,正如Martin 的答案所述,导出道具是最佳实践,因此任何包装器组件都可以使用它们。在我看来,只读标志是不必要的,因为道具应该始终是只读的(如下所述)并且性能不是问题。
长答案:要回答export问题的 -ing 部分,您绝对应该导出 props 接口。以Material UI(MUI)为例;GitHub 上的TypeScript 约定自述文件指出:
- 从 {component}Classes.ts 导出接口 {ComponentName} 类并添加用于生成 api 文档的注释(对于内部组件,可能会或可能不会公开类,但不需要注释)
- 导出接口 {ComponentName}Props
- 始终从组件文件导出 props 接口(使用接口而不是类型)
第二部分和第三部分指出,MUI 开发人员编写的每个公共组件文件都应该导出 props。在编写其 props 扩展 MUI 组件的 props 的组件时,以及在编写我自己的组件时,我利用了这一点。仅此一点就足以说服您导出所有道具的接口。唯一可行的理由是,如果样式指南出于某种原因明确这么说。
以下代码是我当前正在处理的 React + TS 站点中的组件定义。
import type {ButtonProps} from "@mui/material/Button";
import { ThrottleClasses } from "@/store/throttle";
/**
* Props structure for {@link RequestButton}
*/
export interface RequestButtonProps
extends Omit<ButtonProps, "title" | "variant"> {
/**
* Whether or not the form adjacent to this element is valid.
*/
valid: boolean;
/**
* The name of a value in the throttle store to compare against
* to decide if the request can be sent.
*/
throttle?: string;
/**
* The `isLoading` property returned from an RTK query or mutation.
*/
isLoading?: boolean;
/**
* The `isError` property returned from an RTK query or mutation.
*/
isError?: boolean;
/**
* The action phrase which is displayed on the button's tooltip.
*/
title?: React.ReactNode;
/**
* The button's style type, analogous to those defined in {@link ButtonProps}.
*/
variant?: "contained" | "text" | "outlined";
}
/**
* A button to be used when send requests to the backend.
* This component also listens to the throttle state in
* order to prevent excessive requests if necessary.
* This can be done by dispatching a throttle action when this button is clicked,
* and passing the corresponding {@link ThrottleClasses} property to this.
* @props {@link FormSubmitProps}
* @component
*/
export const RequestButton: React.FC<RequestButtonProps> = ({
valid,
children,
throttle,
isLoading,
isError = false,
title = children,
variant = "contained",
...props
}) => {
...
Run Code Online (Sandbox Code Playgroud)
导出 props 接口的另一个鲜为人知的原因(至少我没有听说太多)是自动文档生成。如果您回顾 MUI 引用的第二部分,它还提到“添加用于生成 api 文档的注释”。上面的代码中可以看到这样的一个例子,其中每个属性都有一个简短的解释。
我使用一个名为TypeDoc的优秀工具来生成文档。它的作用是查看文件中的导出和随附的JSDoc样式注释(用双星号表示(JSDoc 是 JavaScript 的类似工具)),并使用它们生成可浏览的静态 HTML 站点。我提到这一点的原因是,要使其发挥作用,您必须导出要记录的项目,因此如果您决定稍后使用它,它可能会派上用场。另外,即使您不使用此工具,当您将鼠标悬停在属性上(甚至在其他文件中)时, VSCode等文本编辑器也会使用这些注释来提供上下文,我个人认为当我不记得某个属性是什么时,这非常有用是为了.
关于readonly标签,我完全同意马丁的观点;重新分配给 props 是非常糟糕的做法,这会使readonly标签变得多余。这在关于重新分配给道具的答案中得到了很好的解释。
在 React 中你永远不应该尝试改变 props。属性是从父组件传递的内容。如果要更改属性,则必须转到父组件并更改正在传递的内容。
关于性能,它在运行时没有开销,因为所有仅 TypeScript 的定义(类型、接口等)都会被 TypeScript 编译器删除,并且不会出现在输出文件中。在编译期间,可能会有一些轻微的开销,但在现实世界的应用程序中,这不会超过几毫秒。
| 归档时间: |
|
| 查看次数: |
2449 次 |
| 最近记录: |