在 React 元件中組織程式碼有時經常被忽視,但在處理高階元件 (HoC)、 forwardRef
和memo
時,事情可能會變得複雜。如果處理不當,可能會導致程式碼混亂且難以維護。本文旨在透過提出一種更易於管理的方式來建立程式碼並提高工作效率來解決這些問題。
forwardRef
和memo
身為 React 開發人員,我經常在組織元件方面遇到困難,尤其是在合併memo
和forwardRef
時。以下的範例取自React TypeScript Cheatsheet ,示範了這個挑戰:
import { forwardRef } from 'react';
interface FancyButtonProps {
type: 'submit' | 'button';
children?: React.ReactNode;
}
export const FancyButton = forwardRef<HTMLButtonElement, FancyButtonProps>((props, ref) => (
<button ref={ref} className="MyClassName" type={props.type}>
{props.children}
</button>
));
根據我自己的經驗,這段程式碼有幾個問題:
與「裸」元件相比,由於元件包裝在forwardRef
中,程式碼顯得混亂。
類型並不是真正處於最佳位置。與元件中使用的實際參數相比, forwardRef
的泛型具有相反的順序: <HTMLButtonElement, FancyButtonProps>
與(props, ref)
。
重構變得很麻煩,因為它需要仔細注意方括號和圓括號。假設您不再需要forwardRef
。即使有了彩虹括號之類的幫助,處理這些括號和圓括號有時也會令人沮喪,尤其是當元件很大時。
如果您想要為元件新增memo
或某些類型的自訂 HoC,以及其中的某些狀態或函數,該怎麼辦?它會變得更加混亂:
import { forwardRef, memo } from 'react';
import { useStyles } from '@/modules/core/styles';
interface FancyButtonProps {
type: 'submit' | 'button';
children?: React.ReactNode;
}
export const FancyButton = memo(
forwardRef<HTMLButtonElement, FancyButtonProps>(({ type, children }, ref) => {
const classes = useStyles();
return <button ref={ref} className={classes.button} type={props.type}>
{children}
</button>
})
);
在厭倦了以這種方式組織元件程式碼時遇到的所有麻煩之後,我最終想出了一種方法來解決這些問題。考慮以下方法:
import { forwardRef, memo } from 'react';
import { useStyles } from '@/modules/core/styles';
interface FancyButtonProps {
type: 'submit' | 'button';
children?: React.ReactNode;
}
const FancyButtonBase = (
{ type, children }: FancyButtonProps,
ref: React.ForwardedRef<HTMLButtonElement>
) => {
const classes = useStyles();
return (
<button ref={ref} className={classes.button} type={type}>
{children}
</button>
);
};
export const FancyButton = memo(forwardRef(FancyButtonBase));
該程式碼是不言自明的。元件的實際程式碼位於名稱帶有Base
後綴的函陣列件中。然後我們匯出下面的元件,以及所有 HoC、 memo
和forwardRef
。
此解決方案具有以下幾個優點:
實際的元件程式碼與 HoC、 memo
和forwardRef
分離,使其類似於「裸」元件。
類型位於它們應該在的位置: (props: FancyButtonProps, ref: React.ForwardedRef<HTMLButtonElement>
。
如果您需要重構此程式碼,例如不再使用ref
,您只需刪除第二個參數和forwardRef
而無需處理方括號和圓括號。
如果需要嵌套的 HoC,加入或修改它們很簡單,並且程式碼仍然可讀:
import { forwardRef, memo } from 'react';
import { useStyles } from '@/modules/core/styles';
import { withWhatever } from '@/modules/core/hocs';
interface FancyButtonProps {
type: 'submit' | 'button';
children?: React.ReactNode;
}
const FancyButtonBase = (
{ type, children }: FancyButtonProps,
ref: React.ForwardedRef<HTMLButtonElement>
) => {
const classes = useStyles();
return (
<button ref={ref} className={classes.button} type={type}>
{children}
</button>
);
};
export const FancyButton = memo(forwardRef(withWhatever(FancyButtonBase)));
這種方法為元件加入了一行程式碼,但顯著提高了可讀性和可維護性。即使不使用任何 HoC、 memo
或forwardRef
,我仍然對「裸」元件執行此操作: export const FancyButton = FancyButtonBase
。
我們可以更進一步,嘗試使用一個非常有用但不太知名的 VSCode 擴充功能來提高我們的工作效率。
下面的 GIF 演示了VSCode 中「資料夾模板」擴充功能的強大功能(載入 GIF 可能需要一點時間):
您只需輸入元件的名稱,瞧!
基本上,您也可以告訴 AI 為您編寫此樣板程式碼,但我發現使用此擴充功能要快得多,而且它是高度可自訂的。
如果您需要我分享我預先定義的 React 特定資料夾範本設置,請在評論中告訴我。
在 React 元件中組織程式碼,尤其是在使用memo
、 forwardRef
和 HoC 時,可能會是一項艱鉅的任務。然而,透過將實際的元件程式碼與 HoC 分開並確保正確的類型聲明,您可以建立更清晰、更易於維護的程式碼。此外,使用 VSCode 中的「資料夾範本」擴充功能等工具可以幫助簡化您的開發流程並提高工作效率。
如果你認為這是一篇好文章,你可能會發現我之前的文章也很有用:
https://dev.to/itswillt/folder-structs-in-react-projects-3dp8
原文出處:https://dev.to/itswillt/organizing-code-in-a-react-component-4coa