本章定位
上一章,我们已经把 Next.js 项目从“页面结构和路由”继续推进到了“页面如何围绕数据进行展示”的阶段。
你已经开始建立这些很关键的认识:
- 页面数据不只有接口请求这一种来源。
- 静态内容、动态内容、用户交互内容经常会同时出现在一个页面里。
- 列表页和详情页是内容型网站里非常核心的两类页面。
- 页面不能只写成功状态,还要考虑加载态、错误态和空状态。
也就是说,到现在为止,你已经不仅能把页面搭起来,也开始知道:
页面里的内容应该怎样围绕数据和状态组织起来。
但当项目继续往前推进时,很快又会遇到另一类问题:
- 文章卡片在首页和列表页都要用,应该复制两份吗?
- 按钮、标签、空状态这些结构反复出现,应该怎么整理?
- 日期格式化、文章筛选、常量配置这些逻辑放哪儿更合适?
- 样式文件越来越多后,怎么避免到处散落?
- 页面组件和通用组件的职责边界怎么区分?
这些问题说明我们已经从“页面能跑起来”进一步走到了:
项目怎样保持清楚、稳定、可继续扩展。
所以这一章,我们会正式进入 Next.js 项目非常重要的一条主线:
组件复用、样式组织与公共模块。
这一章的重点不是为了“看起来更高级”而抽象。
而是为了让你尽早建立一个很重要的工程意识:
项目越往后做,越要学会把重复结构、共用逻辑和公共样式放到更合适的位置。
本章学习目标
学完这一章后,你应该能做到:
- 理解为什么项目一变大,就要开始考虑组件复用和目录整理。
- 知道什么样的页面结构适合提取成公共组件。
- 理解页面组件和通用组件在职责上的区别。
- 学会判断“复用”和“过度抽象”之间的边界。
- 理解样式文件为什么也需要有组织地放置。
- 知道公共工具函数、常量配置和数据函数通常适合放在哪里。
- 能看懂一个适合初学者的 Next.js 项目分层示意。
- 初步建立“组件、样式、工具函数、常量”分层组织的思路。
- 为下一章学习表单、提交与基础后端交互意识做好准备。
一、为什么项目越往后做,越要开始整理结构
刚开始写项目时,内容通常还比较少。
例如:
- 只有几个页面
- 只有几个组件
- 样式文件也不多
- 数据逻辑也比较简单
这时很多代码即使先放得没那么讲究,项目也还能跑。
但只要项目继续往下长,很快就会出现这些情况:
- 同一种卡片结构在多个页面都要用。
- 同一种按钮样式在不同地方反复出现。
- 日期格式化、文字截断、标签颜色映射这些逻辑开始重复。
- 页面文件越来越大。
- 目录里开始堆满“先临时放这里”的文件。
这时候如果不开始整理,项目就会慢慢出现一个问题:
能继续写,但越来越难改。
所以这一章真正要解决的,不是“怎么显得专业”,而是:
怎么让项目在继续增长时,还能保持清楚。
二、什么是组件复用
先给一个当前阶段最够用的理解:
组件复用,就是把多个地方都会用到、结构和职责比较稳定的界面部分提炼出来,避免重复写很多遍。
例如一个内容网站里,下面这些结构就很常见:
- 文章卡片
- 标签组件
- 空状态提示
- 页面标题区
- 分页区域
- 公共按钮
1. 为什么复用不是“少写几行代码”这么简单
表面看,好像只是减少重复代码。
但更重要的是:
让相同职责的界面块,有统一的结构和修改入口。
例如一旦文章卡片需要调整:
- 标题大小
- 摘要行数
- 标签位置
如果你写了三四份不同版本,后面会很难统一。
2. 当前阶段最值得先记住什么
你可以先记住一句话:
复用的核心不是“省代码”,而是让相同职责的内容有更稳定的组织方式。
三、什么样的内容适合提取成公共组件
这一步非常关键。
因为很多初学者一听到“组件复用”,容易走向两个极端:
- 完全不提取,什么都复制粘贴
- 什么都想提取,拆得特别碎
这两个方向都容易出问题。
当前阶段更稳的判断标准是:
同一类结构在多个地方重复出现,并且职责比较清楚,就值得考虑提取。
例如:
1. 文章卡片
首页可能展示推荐文章卡片,列表页也会展示文章卡片。
这时就很适合提一个:
PostCard
2. 标签组件
如果 React、TypeScript、Next.js 这些标签在很多地方都出现,且视觉风格一致,就适合提一个:
Tag
3. 空状态组件
如果多个页面都可能出现:
- 暂无内容
- 搜索结果为空
- 分类下暂无文章
那就很适合提一个:
EmptyState
4. 不一定一开始就提的内容
如果某块结构只在一个页面里出现一次,而且短期也没有复用迹象,就可以先留在页面内部。
这点非常重要。
因为:
不是所有东西都必须马上抽出来。
四、页面组件和通用组件,有什么区别
这是本章最关键的区分之一。
你可以先把它们理解成两类角色。
1. 页面组件更像“页面入口”
例如:
app/page.tsxapp/posts/page.tsxapp/posts/[slug]/page.tsxapp/about/page.tsx
它们更像是在负责:
- 当前页面要拿什么数据
- 当前页面要组合哪些模块
- 当前页面最终展示什么内容
2. 通用组件更像“页面里的可复用零件”
例如:
PostCardTagEmptyStateSectionTitlePagination
它们更像是在负责:
某一小块界面应该怎样展示
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. 当前阶段你先别纠结什么
先别急着追求:
- 是否还能传更多配置
- 是否要支持很多变体
- 是否要做得特别通用
先把“明确职责 + 减少重复”这两件事做好,就已经很好了。
六、什么是“复用的前提是边界清楚”
大纲里有一句很重要的话:
复用的前提是边界清楚,不是所有东西都要抽象。
这句话特别值得停下来理解。
很多初学者第一次开始“重构”时,会特别容易把组件提得过碎。
例如:
- 一个标题单独组件
- 一个时间单独组件
- 一个箭头图标也单独组件
如果这些拆分没有清楚的复用价值,结果往往是:
文件变多了,但项目并没有更清楚。
所以当前阶段更稳的判断方式是:
- 这个结构是不是重复出现了
- 它的职责是不是比较稳定
- 抽出来后页面是不是更容易读了
只要这三点里看不出明显收益,就可以先不急着抽。
七、公共组件通常适合放在哪里
在 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.css1. 哪种方式一定更好
没有绝对答案。
当前阶段更重要的是:
你的样式放置规则要稳定、能解释、自己能找得到。
2. 当前阶段最值得先建立什么习惯
先让样式和组件之间的关系清楚,而不是到处随手放。
十、为什么按钮、标题、卡片这些样式值得统一
因为这些元素通常不是只出现一次。
例如一个项目里可能有很多:
- 主要按钮
- 次要按钮
- 页面大标题
- 模块小标题
- 卡片容器
如果每个地方都临时写一版,后面就会越来越乱。
所以更稳的做法往往是:
先为高频重复的界面块建立统一风格。
这不一定一开始就要上完整设计系统。
你先做到:
- 主按钮风格一致
- 卡片边距和圆角大致一致
- 标题层级视觉有统一规律
就已经很有价值了。
十一、公共工具函数是什么,为什么值得提出来
除了组件,项目里还会慢慢出现另一类重复内容:
不直接渲染界面,但会被很多地方复用的逻辑函数。
例如:
- 格式化日期
- 截断摘要文字
- 根据分类返回标签颜色
- 计算阅读时长
- 过滤文章列表
这类内容不适合塞进页面 JSX 里,也不适合放进通用组件内部。
所以更稳的做法通常是:
提取成工具函数。
十二、工具函数通常适合放在哪里
在当前阶段,一个很常见的目录叫:
lib/
你可以先把它理解成:
放数据函数、工具逻辑和公共处理函数的地方。
例如:
src/ ├── app/ ├── components/ └── lib/ ├── posts.ts ├── format-date.ts ├── get-tag-color.ts └── truncate-text.ts1. 为什么工具函数不适合混在页面里
因为页面更应该负责:
当前页面拿什么数据、组合哪些组件、展示什么内容
而不是同时还承担很多零散工具逻辑。
2. 为什么也不适合把所有函数都叫utils
不是不能叫,而是当前阶段更推荐:
能按职责拆清楚就尽量拆清楚。
例如:
- 数据相关函数放
posts.ts - 日期格式化单独放
format-date.ts
这样比把所有东西塞进一个巨大的utils.ts里更清楚。
十三、常量配置为什么也值得单独放
项目再往下做,你还会慢慢遇到一些内容:
它们不是函数,不是组件,但会被很多地方反复用到。
例如:
- 导航配置
- 分类列表
- 社交链接
- 站点标题
- 页脚文案
这类内容很适合整理成常量配置。
例如:
exportconstsiteNavList=[{label:"首页",href:"/"},{label:"文章",href:"/posts"},{label:"关于",href:"/about"}];1. 为什么常量配置单独放会更稳
因为这样一来:
- 页面结构更清楚
- 修改入口更集中
- 多个组件能共享同一份配置
2. 当前阶段最值得先建立什么意识
你可以先记住:
不是所有会重复使用的内容都应该写死在组件里。
有些更适合变成配置。
十四、页面组件不应该承担太多什么
这一节非常重要。
页面组件最适合承担的是:
- 当前页面的数据准备
- 当前页面的模块组合
- 当前页面的状态分支判断
而不太适合同时承担太多:
- 重复卡片结构
- 到处都能用的按钮结构
- 日期格式化细节
- 导航配置数组
- 很长的样式细节定义
如果这些内容都堆在页面里,页面文件会很快变得很重。
当前阶段更稳的方向是:
页面负责组织,细节逐步下放给组件、工具函数和配置模块。
十五、先看一个适合初学者的分层示意
下面这个结构非常适合拿来建立当前阶段的整体感觉:
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.css1. 为什么这个结构比较稳
因为它已经开始把几类职责分开了:
app/放页面components/放复用界面块lib/放工具和数据函数constants/放配置styles/放样式
2. 当前阶段一定要完全照这个结构吗
不用。
重点不在于目录名字一模一样,而在于:
你有没有开始按职责分层。
这才是本章真正想建立的能力。
十六、什么时候不应该急着提组件
这点也很关键。
有时候一个结构只出现一次,而且页面还在快速变化。
这时如果你太早抽出来,反而可能会出现:
- 组件名字很勉强
- props 越传越多
- 页面和组件两边来回跳,读起来更累
所以当前阶段非常值得建立的一条判断是:
先重复两次以上、职责比较稳定,再考虑提组件,往往更稳。
这不是硬规则,但对初学阶段特别有帮助。
十七、什么时候适合开始统一样式规范
这也不是越晚越好。
通常当你开始明显遇到这些情况时,就可以开始整理了:
- 多个按钮长得不太一样
- 卡片留白和圆角没有统一规律
- 标题层级视觉不稳定
- 相同功能的提示样式各写各的
这时候最值得先统一的,往往不是一切,而是高频元素。
例如:
- 按钮
- 卡片
- 标签
- 页面标题
- 空状态提示
十八、为什么“项目越往后做,越要重视结构分层”
这一点你现在已经能开始感受到了。
因为项目刚开始时,很多问题会被规模掩盖。
但一旦页面、组件、样式、数据函数都在增加,混乱会被迅速放大。
结构分层的价值就在于:
- 让文件更容易找
- 让修改影响范围更容易判断
- 让多人协作更容易分工
- 让后续优化更容易落地
这就是为什么说:
分层不是形式,而是在为项目继续增长提前留空间。
十九、这一章最容易踩的几个坑
这一节建议你认真看。
因为这一章开始,很多“结构问题”不会立刻报错,但会慢慢拖累整个项目。
1. 坑一:什么都不抽,所有内容都堆在页面里
短期看写得快,长期会越来越难改。
2. 坑二:什么都想抽,拆得过碎
这样会导致:
- 文件数量暴涨
- 命名越来越勉强
- 阅读成本变高
3. 坑三:页面组件和通用组件职责混乱
这样会让:
- 页面不清楚
- 组件不通用
- props 越来越混乱
4. 坑四:所有工具函数都塞进一个超大utils.ts
这样短期省事,后面很难维护。
5. 坑五:样式文件没有规则,到处散落
这样会导致改动时很难判断影响范围。
6. 坑六:为了复用而复用
要记住:
复用是为了让结构更清楚,不是为了制造更多抽象层。
二十、本章实践练习
这一章的练习重点,是把“组件、样式、工具逻辑、配置”真正开始分层。
1. 练习 1:提取一个PostCard组件
请你把首页和文章列表页中重复的文章卡片结构提取成:
PostCard
要求:
- 支持标题、摘要、分类、日期、跳转链接
- 两个页面共用同一个组件
这个练习会帮助你真正理解:
什么叫“结构重复且职责稳定”的组件适合复用。
2. 练习 2:整理一个日期格式化函数
请你把日期显示逻辑提取成单独函数,例如:
formatDate
这个练习会帮助你建立:
页面不应该承担所有细节逻辑。
3. 练习 3:把导航配置提取成常量
请你把站点导航整理成单独配置文件。
例如:
- 首页
- 文章
- 关于
- 联系
这个练习会帮助你真正理解:
有些重复内容更适合变成配置,而不是写死在组件里。
4. 练习 4:整理一个最小可用的目录结构
请你尝试把当前项目至少整理出下面几层:
app/components/lib/constants/styles/
这个练习的重点是:
让你真正从“写页面”开始走向“组织项目”。
二十一、学习重点提示
这一章请你重点记住下面这些话:
- 组件复用的核心,不只是省代码,而是让相同职责的界面结构有稳定的组织方式。
- 页面组件更适合负责页面组织,通用组件更适合负责局部结构表达。
- 不是所有东西都要抽象,复用的前提是边界清楚。
- 公共工具函数、数据函数、配置项和样式文件,也都需要有组织地放置。
- 样式不是附属品,它也是项目结构的一部分。
- 与其把所有函数塞进一个大文件,不如按职责慢慢拆清楚。
- 目录结构不必一开始完美,但要尽早建立按职责分层的意识。
- 项目越往后做,越要重视组件、样式、工具逻辑和配置的分层。
如果你只记一句话,请记住:
这一章真正要建立的,不只是“会抽几个组件”,而是“会在项目增长时,把页面、复用结构、样式和公共逻辑逐步放到更合适的位置”。
二十二、本章小结
这一章,我们正式把 Next.js 从“页面结构与数据展示”推进到了“项目怎样继续保持清楚和可扩展”的阶段。
你已经理解了:
- 为什么项目一变大,就要开始考虑组件复用和目录整理
- 什么样的结构适合提取成公共组件
- 页面组件和通用组件在职责上的区别
- 为什么样式文件也需要组织
- 工具函数、常量配置和数据函数通常适合放在哪里
- 为什么复用的前提是边界清楚
- 为什么项目越往后做,越要重视结构分层
更重要的是,你开始真正建立一种很关键的工程意识:
一个项目能不能长期维护,不只看它能不能运行,还要看它能不能在增长过程中继续保持清楚。
这一步非常关键。
因为从这里开始,你已经不只是在写页面和拿数据,而是在真正进入:
Next.js 项目结构整理与组件复用的基础阶段。
二十三、课后思考题
请你认真思考下面这些问题:
- 为什么说组件复用的核心,不只是减少重复代码?
- 页面组件和通用组件在职责上最大的区别是什么?
- 什么样的结构更适合提取成公共组件?什么样的结构可以暂时留在页面里?
- 为什么说“复用的前提是边界清楚”?
- 为什么样式文件和工具函数也需要结构化放置?
- 为什么把所有函数都塞进一个大
utils.ts里通常不是长久之计? - 如果你的博客项目越写越大,你觉得最先值得统一的组件和样式会是哪几类?
建议你把这些问题用自己的话写下来。
只要你能把这些问题讲清楚,说明你已经真正进入 Next.js 项目分层与复用的主线了。
二十四、下一篇预告
下一章我们会继续进入:
从零开始学前端 | 第四十一章:表单、提交与基础后端交互意识
你会开始真正接触这些内容:
- 联系表单或留言表单应该怎样组织
- 提交按钮、校验、错误提示、成功提示应该怎样配合
- 用户输入和页面状态怎样一起工作
- 前后端交互流程最基础的认知是什么
也就是说,下一章开始,我们会从“组件复用、样式组织与公共模块”,继续走到:
Next.js 页面输入、提交与交互反馈的下一步。