从零开始学前端 | 第四十章:组件复用、样式组织与公共模块
2026/7/22 10:22:52 网站建设 项目流程

本章定位

上一章,我们已经把 Next.js 项目从“页面结构和路由”继续推进到了“页面如何围绕数据进行展示”的阶段。

你已经开始建立这些很关键的认识:

  1. 页面数据不只有接口请求这一种来源。
  2. 静态内容、动态内容、用户交互内容经常会同时出现在一个页面里。
  3. 列表页和详情页是内容型网站里非常核心的两类页面。
  4. 页面不能只写成功状态,还要考虑加载态、错误态和空状态。

也就是说,到现在为止,你已经不仅能把页面搭起来,也开始知道:

页面里的内容应该怎样围绕数据和状态组织起来。

但当项目继续往前推进时,很快又会遇到另一类问题:

  1. 文章卡片在首页和列表页都要用,应该复制两份吗?
  2. 按钮、标签、空状态这些结构反复出现,应该怎么整理?
  3. 日期格式化、文章筛选、常量配置这些逻辑放哪儿更合适?
  4. 样式文件越来越多后,怎么避免到处散落?
  5. 页面组件和通用组件的职责边界怎么区分?

这些问题说明我们已经从“页面能跑起来”进一步走到了:

项目怎样保持清楚、稳定、可继续扩展。

所以这一章,我们会正式进入 Next.js 项目非常重要的一条主线:

组件复用、样式组织与公共模块。

这一章的重点不是为了“看起来更高级”而抽象。

而是为了让你尽早建立一个很重要的工程意识:

项目越往后做,越要学会把重复结构、共用逻辑和公共样式放到更合适的位置。

本章学习目标

学完这一章后,你应该能做到:

  1. 理解为什么项目一变大,就要开始考虑组件复用和目录整理。
  2. 知道什么样的页面结构适合提取成公共组件。
  3. 理解页面组件和通用组件在职责上的区别。
  4. 学会判断“复用”和“过度抽象”之间的边界。
  5. 理解样式文件为什么也需要有组织地放置。
  6. 知道公共工具函数、常量配置和数据函数通常适合放在哪里。
  7. 能看懂一个适合初学者的 Next.js 项目分层示意。
  8. 初步建立“组件、样式、工具函数、常量”分层组织的思路。
  9. 为下一章学习表单、提交与基础后端交互意识做好准备。

一、为什么项目越往后做,越要开始整理结构

刚开始写项目时,内容通常还比较少。

例如:

  • 只有几个页面
  • 只有几个组件
  • 样式文件也不多
  • 数据逻辑也比较简单

这时很多代码即使先放得没那么讲究,项目也还能跑。

但只要项目继续往下长,很快就会出现这些情况:

  1. 同一种卡片结构在多个页面都要用。
  2. 同一种按钮样式在不同地方反复出现。
  3. 日期格式化、文字截断、标签颜色映射这些逻辑开始重复。
  4. 页面文件越来越大。
  5. 目录里开始堆满“先临时放这里”的文件。

这时候如果不开始整理,项目就会慢慢出现一个问题:

能继续写,但越来越难改。

所以这一章真正要解决的,不是“怎么显得专业”,而是:

怎么让项目在继续增长时,还能保持清楚。

二、什么是组件复用

先给一个当前阶段最够用的理解:

组件复用,就是把多个地方都会用到、结构和职责比较稳定的界面部分提炼出来,避免重复写很多遍。

例如一个内容网站里,下面这些结构就很常见:

  • 文章卡片
  • 标签组件
  • 空状态提示
  • 页面标题区
  • 分页区域
  • 公共按钮

1. 为什么复用不是“少写几行代码”这么简单

表面看,好像只是减少重复代码。

但更重要的是:

让相同职责的界面块,有统一的结构和修改入口。

例如一旦文章卡片需要调整:

  • 标题大小
  • 摘要行数
  • 标签位置

如果你写了三四份不同版本,后面会很难统一。

2. 当前阶段最值得先记住什么

你可以先记住一句话:

复用的核心不是“省代码”,而是让相同职责的内容有更稳定的组织方式。

三、什么样的内容适合提取成公共组件

这一步非常关键。

因为很多初学者一听到“组件复用”,容易走向两个极端:

  1. 完全不提取,什么都复制粘贴
  2. 什么都想提取,拆得特别碎

这两个方向都容易出问题。

当前阶段更稳的判断标准是:

同一类结构在多个地方重复出现,并且职责比较清楚,就值得考虑提取。

例如:

1. 文章卡片

首页可能展示推荐文章卡片,列表页也会展示文章卡片。

这时就很适合提一个:

PostCard

2. 标签组件

如果 React、TypeScript、Next.js 这些标签在很多地方都出现,且视觉风格一致,就适合提一个:

Tag

3. 空状态组件

如果多个页面都可能出现:

  • 暂无内容
  • 搜索结果为空
  • 分类下暂无文章

那就很适合提一个:

EmptyState

4. 不一定一开始就提的内容

如果某块结构只在一个页面里出现一次,而且短期也没有复用迹象,就可以先留在页面内部。

这点非常重要。

因为:

不是所有东西都必须马上抽出来。

四、页面组件和通用组件,有什么区别

这是本章最关键的区分之一。

你可以先把它们理解成两类角色。

1. 页面组件更像“页面入口”

例如:

  • app/page.tsx
  • app/posts/page.tsx
  • app/posts/[slug]/page.tsx
  • app/about/page.tsx

它们更像是在负责:

  1. 当前页面要拿什么数据
  2. 当前页面要组合哪些模块
  3. 当前页面最终展示什么内容

2. 通用组件更像“页面里的可复用零件”

例如:

  • PostCard
  • Tag
  • EmptyState
  • SectionTitle
  • Pagination

它们更像是在负责:

某一小块界面应该怎样展示

3. 为什么一定要建立这个区分

因为如果页面和组件职责混在一起,后面会很容易出现:

  • 页面既拿数据又管很多视觉细节
  • 通用组件里混进了很多页面专属逻辑
  • 组件边界越来越模糊

当前阶段更稳的理解是:

页面组件负责组织页面,通用组件负责表达局部结构。

五、先看一个文章卡片为什么值得提出来

假设你的网站里:

  • 首页展示“推荐文章”
  • 文章列表页展示“全部文章”

这两个地方都在渲染一类很像的结构:

  1. 标题
  2. 摘要
  3. 分类标签
  4. 发布时间
  5. 跳转链接

如果你在两个页面分别写一遍,很快就会遇到这些问题:

  1. 样式不一定完全一致
  2. 结构改动要改两处
  3. 后面再加第三个页面又得复制一次

所以当前阶段很适合提成:

interface PostCardProps { title: string; summary: string; category: string; publishDate: string; href: string; }
import Link from "next/link"; export function PostCard(props: PostCardProps) { return ( <article className="post-card"> <p className="post-card__meta"> {props.category} · {props.publishDate} </p> <h2 className="post-card__title"> <Link href={props.href}>{props.title}</Link> </h2> <p className="post-card__summary">{props.summary}</p> </article> ); }

1. 为什么这个例子特别适合入门理解复用

因为它的职责很稳定:

就是在不同页面里展示一张文章简介卡片。

2. 当前阶段你先别纠结什么

先别急着追求:

  • 是否还能传更多配置
  • 是否要支持很多变体
  • 是否要做得特别通用

先把“明确职责 + 减少重复”这两件事做好,就已经很好了。

六、什么是“复用的前提是边界清楚”

大纲里有一句很重要的话:

复用的前提是边界清楚,不是所有东西都要抽象。

这句话特别值得停下来理解。

很多初学者第一次开始“重构”时,会特别容易把组件提得过碎。

例如:

  • 一个标题单独组件
  • 一个时间单独组件
  • 一个箭头图标也单独组件

如果这些拆分没有清楚的复用价值,结果往往是:

文件变多了,但项目并没有更清楚。

所以当前阶段更稳的判断方式是:

  1. 这个结构是不是重复出现了
  2. 它的职责是不是比较稳定
  3. 抽出来后页面是不是更容易读了

只要这三点里看不出明显收益,就可以先不急着抽。

七、公共组件通常适合放在哪里

在 Next.js 项目里,一个比较常见、也比较适合初学者的做法是:

把通用组件集中放进components/目录。

例如:

src/ ├── app/ ├── components/ │ ├── post-card.tsx │ ├── tag.tsx │ ├── empty-state.tsx │ └── section-title.tsx └── lib/

1. 为什么这样放更清楚

因为它能帮助你一眼区分:

  • app/里是页面和路由
  • components/里是可复用界面块

2. 当前阶段要不要再继续细分很多层

不用急。

如果项目还在中小规模阶段,先把页面和公共组件分开,已经非常够用了。

八、样式文件为什么也要组织

这一点非常重要,但又常被忽略。

很多人一开始只会整理组件文件,却不太会整理样式。

结果很容易变成:

  • 全局样式越来越长
  • 各处类名混在一起
  • 修改一个按钮样式时,不知道影响到哪里

所以样式文件同样需要有组织。

你可以先记住一句话:

样式不是“写上去就行”,它也属于项目结构的一部分。

九、初学阶段样式通常可以怎么放

当前阶段更适合从简单清楚的方式开始。

例如:

src/ ├── app/ │ └── globals.css ├── components/ │ ├── post-card.tsx │ └── tag.tsx └── styles/ ├── post-card.css └── tag.css

或者你也可以采用“组件和样式相邻”的思路:

src/ ├── components/ │ ├── post-card.tsx │ ├── post-card.css │ ├── tag.tsx │ └── tag.css

1. 哪种方式一定更好

没有绝对答案。

当前阶段更重要的是:

你的样式放置规则要稳定、能解释、自己能找得到。

2. 当前阶段最值得先建立什么习惯

先让样式和组件之间的关系清楚,而不是到处随手放。

十、为什么按钮、标题、卡片这些样式值得统一

因为这些元素通常不是只出现一次。

例如一个项目里可能有很多:

  • 主要按钮
  • 次要按钮
  • 页面大标题
  • 模块小标题
  • 卡片容器

如果每个地方都临时写一版,后面就会越来越乱。

所以更稳的做法往往是:

先为高频重复的界面块建立统一风格。

这不一定一开始就要上完整设计系统。

你先做到:

  1. 主按钮风格一致
  2. 卡片边距和圆角大致一致
  3. 标题层级视觉有统一规律

就已经很有价值了。

十一、公共工具函数是什么,为什么值得提出来

除了组件,项目里还会慢慢出现另一类重复内容:

不直接渲染界面,但会被很多地方复用的逻辑函数。

例如:

  • 格式化日期
  • 截断摘要文字
  • 根据分类返回标签颜色
  • 计算阅读时长
  • 过滤文章列表

这类内容不适合塞进页面 JSX 里,也不适合放进通用组件内部。

所以更稳的做法通常是:

提取成工具函数。

十二、工具函数通常适合放在哪里

在当前阶段,一个很常见的目录叫:

lib/

你可以先把它理解成:

放数据函数、工具逻辑和公共处理函数的地方。

例如:

src/ ├── app/ ├── components/ └── lib/ ├── posts.ts ├── format-date.ts ├── get-tag-color.ts └── truncate-text.ts

1. 为什么工具函数不适合混在页面里

因为页面更应该负责:

当前页面拿什么数据、组合哪些组件、展示什么内容

而不是同时还承担很多零散工具逻辑。

2. 为什么也不适合把所有函数都叫utils

不是不能叫,而是当前阶段更推荐:

能按职责拆清楚就尽量拆清楚。

例如:

  • 数据相关函数放posts.ts
  • 日期格式化单独放format-date.ts

这样比把所有东西塞进一个巨大的utils.ts里更清楚。

十三、常量配置为什么也值得单独放

项目再往下做,你还会慢慢遇到一些内容:

它们不是函数,不是组件,但会被很多地方反复用到。

例如:

  • 导航配置
  • 分类列表
  • 社交链接
  • 站点标题
  • 页脚文案

这类内容很适合整理成常量配置。

例如:

exportconstsiteNavList=[{label:"首页",href:"/"},{label:"文章",href:"/posts"},{label:"关于",href:"/about"}];

1. 为什么常量配置单独放会更稳

因为这样一来:

  • 页面结构更清楚
  • 修改入口更集中
  • 多个组件能共享同一份配置

2. 当前阶段最值得先建立什么意识

你可以先记住:

不是所有会重复使用的内容都应该写死在组件里。

有些更适合变成配置。

十四、页面组件不应该承担太多什么

这一节非常重要。

页面组件最适合承担的是:

  1. 当前页面的数据准备
  2. 当前页面的模块组合
  3. 当前页面的状态分支判断

而不太适合同时承担太多:

  • 重复卡片结构
  • 到处都能用的按钮结构
  • 日期格式化细节
  • 导航配置数组
  • 很长的样式细节定义

如果这些内容都堆在页面里,页面文件会很快变得很重。

当前阶段更稳的方向是:

页面负责组织,细节逐步下放给组件、工具函数和配置模块。

十五、先看一个适合初学者的分层示意

下面这个结构非常适合拿来建立当前阶段的整体感觉:

src/ ├── app/ │ ├── layout.tsx │ ├── page.tsx │ ├── about/ │ │ └── page.tsx │ └── posts/ │ ├── page.tsx │ └── [slug]/ │ └── page.tsx ├── components/ │ ├── post-card.tsx │ ├── tag.tsx │ ├── empty-state.tsx │ ├── section-title.tsx │ └── site-header.tsx ├── lib/ │ ├── posts.ts │ ├── format-date.ts │ └── truncate-text.ts ├── constants/ │ └── site.ts └── styles/ ├── globals.css ├── post-card.css └── tag.css

1. 为什么这个结构比较稳

因为它已经开始把几类职责分开了:

  • app/放页面
  • components/放复用界面块
  • lib/放工具和数据函数
  • constants/放配置
  • styles/放样式

2. 当前阶段一定要完全照这个结构吗

不用。

重点不在于目录名字一模一样,而在于:

你有没有开始按职责分层。

这才是本章真正想建立的能力。

十六、什么时候不应该急着提组件

这点也很关键。

有时候一个结构只出现一次,而且页面还在快速变化。

这时如果你太早抽出来,反而可能会出现:

  1. 组件名字很勉强
  2. props 越传越多
  3. 页面和组件两边来回跳,读起来更累

所以当前阶段非常值得建立的一条判断是:

先重复两次以上、职责比较稳定,再考虑提组件,往往更稳。

这不是硬规则,但对初学阶段特别有帮助。

十七、什么时候适合开始统一样式规范

这也不是越晚越好。

通常当你开始明显遇到这些情况时,就可以开始整理了:

  1. 多个按钮长得不太一样
  2. 卡片留白和圆角没有统一规律
  3. 标题层级视觉不稳定
  4. 相同功能的提示样式各写各的

这时候最值得先统一的,往往不是一切,而是高频元素。

例如:

  • 按钮
  • 卡片
  • 标签
  • 页面标题
  • 空状态提示

十八、为什么“项目越往后做,越要重视结构分层”

这一点你现在已经能开始感受到了。

因为项目刚开始时,很多问题会被规模掩盖。

但一旦页面、组件、样式、数据函数都在增加,混乱会被迅速放大。

结构分层的价值就在于:

  1. 让文件更容易找
  2. 让修改影响范围更容易判断
  3. 让多人协作更容易分工
  4. 让后续优化更容易落地

这就是为什么说:

分层不是形式,而是在为项目继续增长提前留空间。

十九、这一章最容易踩的几个坑

这一节建议你认真看。

因为这一章开始,很多“结构问题”不会立刻报错,但会慢慢拖累整个项目。

1. 坑一:什么都不抽,所有内容都堆在页面里

短期看写得快,长期会越来越难改。

2. 坑二:什么都想抽,拆得过碎

这样会导致:

  • 文件数量暴涨
  • 命名越来越勉强
  • 阅读成本变高

3. 坑三:页面组件和通用组件职责混乱

这样会让:

  • 页面不清楚
  • 组件不通用
  • props 越来越混乱

4. 坑四:所有工具函数都塞进一个超大utils.ts

这样短期省事,后面很难维护。

5. 坑五:样式文件没有规则,到处散落

这样会导致改动时很难判断影响范围。

6. 坑六:为了复用而复用

要记住:

复用是为了让结构更清楚,不是为了制造更多抽象层。

二十、本章实践练习

这一章的练习重点,是把“组件、样式、工具逻辑、配置”真正开始分层。

1. 练习 1:提取一个PostCard组件

请你把首页和文章列表页中重复的文章卡片结构提取成:

PostCard

要求:

  1. 支持标题、摘要、分类、日期、跳转链接
  2. 两个页面共用同一个组件

这个练习会帮助你真正理解:

什么叫“结构重复且职责稳定”的组件适合复用。

2. 练习 2:整理一个日期格式化函数

请你把日期显示逻辑提取成单独函数,例如:

formatDate

这个练习会帮助你建立:

页面不应该承担所有细节逻辑。

3. 练习 3:把导航配置提取成常量

请你把站点导航整理成单独配置文件。

例如:

  • 首页
  • 文章
  • 关于
  • 联系

这个练习会帮助你真正理解:

有些重复内容更适合变成配置,而不是写死在组件里。

4. 练习 4:整理一个最小可用的目录结构

请你尝试把当前项目至少整理出下面几层:

  • app/
  • components/
  • lib/
  • constants/
  • styles/

这个练习的重点是:

让你真正从“写页面”开始走向“组织项目”。

二十一、学习重点提示

这一章请你重点记住下面这些话:

  1. 组件复用的核心,不只是省代码,而是让相同职责的界面结构有稳定的组织方式。
  2. 页面组件更适合负责页面组织,通用组件更适合负责局部结构表达。
  3. 不是所有东西都要抽象,复用的前提是边界清楚。
  4. 公共工具函数、数据函数、配置项和样式文件,也都需要有组织地放置。
  5. 样式不是附属品,它也是项目结构的一部分。
  6. 与其把所有函数塞进一个大文件,不如按职责慢慢拆清楚。
  7. 目录结构不必一开始完美,但要尽早建立按职责分层的意识。
  8. 项目越往后做,越要重视组件、样式、工具逻辑和配置的分层。

如果你只记一句话,请记住:

这一章真正要建立的,不只是“会抽几个组件”,而是“会在项目增长时,把页面、复用结构、样式和公共逻辑逐步放到更合适的位置”。

二十二、本章小结

这一章,我们正式把 Next.js 从“页面结构与数据展示”推进到了“项目怎样继续保持清楚和可扩展”的阶段。

你已经理解了:

  • 为什么项目一变大,就要开始考虑组件复用和目录整理
  • 什么样的结构适合提取成公共组件
  • 页面组件和通用组件在职责上的区别
  • 为什么样式文件也需要组织
  • 工具函数、常量配置和数据函数通常适合放在哪里
  • 为什么复用的前提是边界清楚
  • 为什么项目越往后做,越要重视结构分层

更重要的是,你开始真正建立一种很关键的工程意识:

一个项目能不能长期维护,不只看它能不能运行,还要看它能不能在增长过程中继续保持清楚。

这一步非常关键。

因为从这里开始,你已经不只是在写页面和拿数据,而是在真正进入:

Next.js 项目结构整理与组件复用的基础阶段。

二十三、课后思考题

请你认真思考下面这些问题:

  1. 为什么说组件复用的核心,不只是减少重复代码?
  2. 页面组件和通用组件在职责上最大的区别是什么?
  3. 什么样的结构更适合提取成公共组件?什么样的结构可以暂时留在页面里?
  4. 为什么说“复用的前提是边界清楚”?
  5. 为什么样式文件和工具函数也需要结构化放置?
  6. 为什么把所有函数都塞进一个大utils.ts里通常不是长久之计?
  7. 如果你的博客项目越写越大,你觉得最先值得统一的组件和样式会是哪几类?

建议你把这些问题用自己的话写下来。

只要你能把这些问题讲清楚,说明你已经真正进入 Next.js 项目分层与复用的主线了。

二十四、下一篇预告

下一章我们会继续进入:

从零开始学前端 | 第四十一章:表单、提交与基础后端交互意识

你会开始真正接触这些内容:

  • 联系表单或留言表单应该怎样组织
  • 提交按钮、校验、错误提示、成功提示应该怎样配合
  • 用户输入和页面状态怎样一起工作
  • 前后端交互流程最基础的认知是什么

也就是说,下一章开始,我们会从“组件复用、样式组织与公共模块”,继续走到:

Next.js 页面输入、提交与交互反馈的下一步。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询