一、组件拆分不是为了“文件变多”
我以前对组件拆分有个误解,总觉得它会让项目里多很多文件,看起来更复杂。后来我才慢慢意识到,拆分真正的目的不是“文件数量”,而是让每个文件只承担一种清楚的责任。
比如:
PostCard只负责展示文章卡片SiteHeader只负责导航ThemeToggle只负责主题切换
当职责足够单一时,后面排查问题会轻松很多。
二、一个组件什么时候开始危险
我一般会把下面这些信号当作“组件快失控了”的提醒:
| 信号 | 说明 |
|---|---|
| 文件越来越长 | 说明职责开始堆叠 |
| JSX 重复很多 | 说明有重复结构可以提取 |
| 同时处理数据、交互、样式 | 说明边界不清 |
| 改一小点却要看半天 | 说明可读性已经下降 |
如果一个组件同时负责请求数据、处理状态、弹窗、筛选、分页、展示和跳转,那它基本已经不是一个“单一职责组件”了。
三、我会怎么拆一个页面
我现在更喜欢从页面结构开始往下拆。
比如博客列表页,我不会一上来就写 200 行 JSX,而会先想成这样:
<main>
<BlogHero />
<BlogFilterPanel />
<BlogPostResults />
<BlogPagination />
</main>这时候页面组件只负责组织区块,真正的展示细节交给子组件。
这个思路的好处是:页面层看起来像目录,而不是像一大坨实现细节。
四、什么时候该抽成通用组件
如果某块结构在两个页面里都会出现,我就会开始考虑是不是值得通用化。
例如:
- 标题区块:
SectionHeading - 标签集合:
TagList - 文章卡片:
PostCard - 项目卡片:
ProjectCard
这种组件有一个共同点:它们展示的是“某一类稳定结构”,而不是页面里的临时逻辑。
五、一个不好的拆分长什么样
并不是拆得越细越好。
如果你把一个很自然的结构硬拆成:
CardTitleCardDescriptionCardFooterActionCardMetaRow
但这些东西只在一个地方用,而且拆完后反而要来回跳文件,那就不是好的拆分。
好的拆分应该满足两件事:
- 读页面时更容易理解
- 修改某块时更容易定位
六、命名为什么影响这么大
命名会直接影响你能不能快速理解组件责任。
下面这个例子就很典型:
const data = [];
const item = {};
const handleClick = () => {};这些名字不是错,但太泛了。过两周再回来,你很难第一眼知道它们到底在处理什么。
相比之下:
const blogPosts = [];
const selectedPost = {};
const handleOpenPostDetail = () => {};会清楚很多。
组件名也是一样。PostCard 一看就知道是文章卡片,ThingBox 就完全没有帮助。
七、我现在会怎么判断“该不该拆”
我通常会问自己 3 个问题:
- 这块 JSX 会不会复用?
- 这块是不是已经有独立职责?
- 拆出去之后,页面是不是更容易读?
如果三个问题里有两个答案是“会”,那就很值得拆。
八、一个很实际的小原则
对初学阶段来说,我觉得“一个文件先尽量控制在 100 行左右”是个很有帮助的提醒。
这不是死规则,但它会逼着我在文件变大之前先停下来想一想:
- 这里是不是已经有重复结构了?
- 这里的逻辑是不是能挪出去?
- 这个组件是不是开始承担太多事了?
很多可维护性问题,其实都是在文件变得太大时才慢慢显形的。