⚛️ 在 React 组件中组织代码

2025-06-07

⚛️ 在 React 组件中组织代码

React 组件中的代码组织方式常常被忽视,但在处理高阶组件 (HoC)、forwardRef和 时,事情可能会变得复杂memo。如果处理不当,可能会导致代码混乱且难以维护。本文旨在通过提出一种更易于管理的代码结构方法来提高您的工作效率,从而解决这些问题。

1️⃣在 React 组件中管理 HoC forwardRefmemo

问题陈述

作为一名 React 开发者,我经常在组织组件时遇到困难,尤其是在合并memo和的时候forwardRef。下面这个取自React TypeScript 备忘单的示例演示了这一挑战:



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>
));


Enter fullscreen mode Exit fullscreen mode

根据我自己的经验,此代码存在几个问题:

  • 由于组件被包裹在内,因此与“裸”组件相比,代码显得比较混乱forwardRef
  • 类型实际上并非处于最佳位置。 的泛型顺序forwardRef与组件中使用的实际参数相反:<HTMLButtonElement, FancyButtonProps>vs (props, ref)
  • 重构变得繁琐,因为它需要仔细处理括号和圆括号。假设你不再需要forwardRef……即使借助像 Rainbow Brackets 这样的东西,处理这些括号和圆括号有时也会令人沮丧,尤其是在组件很大的时候。
  • 如果你想在组件中添加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>
  })
);


Enter fullscreen mode Exit fullscreen mode

建议的解决方案

在厌倦了以这种方式组织组件代码所带来的所有麻烦之后,我最终想出了一个解决这些问题的方法。请考虑以下方法:



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));


Enter fullscreen mode Exit fullscreen mode

代码一目了然。组件的实际代码位于一个名称带有Base后缀的函数组件中。然后,我们导出下面的组件,以及所有的高阶组件、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)));


Enter fullscreen mode Exit fullscreen mode

这种方法只会在组件中添加一行代码,但却显著提高了可读性和可维护性。即使不使用任何高阶组件memo、 或forwardRef,我仍然会针对“裸”组件这样做:export const FancyButton = FancyButtonBase

我们可以更进一步,尝试使用非常有用但不为人所知的 VSCode 扩展来提高我们的工作效率。

2️⃣ 使用“文件夹模板”扩展提高生产力

下面的 GIF 演示了VSCode 中“文件夹模板”扩展的强大功能(GIF 可能需要一点时间来加载):

文件夹模板扩展演示

您只需输入组件的名称,瞧!

基本上,您也可以告诉 AI 为您编写这个样板代码,但我发现使用此扩展更快,并且高度可定制。

如果您需要我分享我预定义的 React 特定文件夹模板设置,请在评论中告诉我。

🏁 结论

在 React 组件中组织代码,尤其是在使用memoforwardRef和 HoC 时,可能是一项艰巨的任务。但是,通过将实际的组件代码与 HoC 分离并确保正确的类型声明,您可以创建更简洁、更易于维护的代码。此外,使用 VSCode 中“文件夹模板”扩展等工具可以帮助简化开发流程并提高生产力。

如果您认为这是一篇好文章,那么您可能也会发现我之前的文章很有用:


如果您对前端开发和 Web 开发感兴趣,请关注我并查看下面个人资料中我的文章。

文章来源:https://dev.to/itswillt/organizing-code-in-a-react-component-4coa
PREV
面向前端开发人员的 UI/UX 技巧(第一部分)
NEXT
让我们构建并部署一个全栈 MERN Web 应用程序