从零开始学前端 | 第四十章:组件复用、样式组织与公共模块 📅 2026/7/22 10:22:53 本章定位上一章我们已经把 Next.js 项目从“页面结构和路由”继续推进到了“页面如何围绕数据进行展示”的阶段。你已经开始建立这些很关键的认识页面数据不只有接口请求这一种来源。静态内容、动态内容、用户交互内容经常会同时出现在一个页面里。列表页和详情页是内容型网站里非常核心的两类页面。页面不能只写成功状态还要考虑加载态、错误态和空状态。也就是说到现在为止你已经不仅能把页面搭起来也开始知道页面里的内容应该怎样围绕数据和状态组织起来。但当项目继续往前推进时很快又会遇到另一类问题文章卡片在首页和列表页都要用应该复制两份吗按钮、标签、空状态这些结构反复出现应该怎么整理日期格式化、文章筛选、常量配置这些逻辑放哪儿更合适样式文件越来越多后怎么避免到处散落页面组件和通用组件的职责边界怎么区分这些问题说明我们已经从“页面能跑起来”进一步走到了项目怎样保持清楚、稳定、可继续扩展。所以这一章我们会正式进入 Next.js 项目非常重要的一条主线组件复用、样式组织与公共模块。这一章的重点不是为了“看起来更高级”而抽象。而是为了让你尽早建立一个很重要的工程意识项目越往后做越要学会把重复结构、共用逻辑和公共样式放到更合适的位置。本章学习目标学完这一章后你应该能做到理解为什么项目一变大就要开始考虑组件复用和目录整理。知道什么样的页面结构适合提取成公共组件。理解页面组件和通用组件在职责上的区别。学会判断“复用”和“过度抽象”之间的边界。理解样式文件为什么也需要有组织地放置。知道公共工具函数、常量配置和数据函数通常适合放在哪里。能看懂一个适合初学者的 Next.js 项目分层示意。初步建立“组件、样式、工具函数、常量”分层组织的思路。为下一章学习表单、提交与基础后端交互意识做好准备。一、为什么项目越往后做越要开始整理结构刚开始写项目时内容通常还比较少。例如只有几个页面只有几个组件样式文件也不多数据逻辑也比较简单这时很多代码即使先放得没那么讲究项目也还能跑。但只要项目继续往下长很快就会出现这些情况同一种卡片结构在多个页面都要用。同一种按钮样式在不同地方反复出现。日期格式化、文字截断、标签颜色映射这些逻辑开始重复。页面文件越来越大。目录里开始堆满“先临时放这里”的文件。这时候如果不开始整理项目就会慢慢出现一个问题能继续写但越来越难改。所以这一章真正要解决的不是“怎么显得专业”而是怎么让项目在继续增长时还能保持清楚。二、什么是组件复用先给一个当前阶段最够用的理解组件复用就是把多个地方都会用到、结构和职责比较稳定的界面部分提炼出来避免重复写很多遍。例如一个内容网站里下面这些结构就很常见文章卡片标签组件空状态提示页面标题区分页区域公共按钮1. 为什么复用不是“少写几行代码”这么简单表面看好像只是减少重复代码。但更重要的是让相同职责的界面块有统一的结构和修改入口。例如一旦文章卡片需要调整标题大小摘要行数标签位置如果你写了三四份不同版本后面会很难统一。2. 当前阶段最值得先记住什么你可以先记住一句话复用的核心不是“省代码”而是让相同职责的内容有更稳定的组织方式。三、什么样的内容适合提取成公共组件这一步非常关键。因为很多初学者一听到“组件复用”容易走向两个极端完全不提取什么都复制粘贴什么都想提取拆得特别碎这两个方向都容易出问题。当前阶段更稳的判断标准是同一类结构在多个地方重复出现并且职责比较清楚就值得考虑提取。例如1. 文章卡片首页可能展示推荐文章卡片列表页也会展示文章卡片。这时就很适合提一个PostCard2. 标签组件如果 React、TypeScript、Next.js 这些标签在很多地方都出现且视觉风格一致就适合提一个Tag3. 空状态组件如果多个页面都可能出现暂无内容搜索结果为空分类下暂无文章那就很适合提一个EmptyState4. 不一定一开始就提的内容如果某块结构只在一个页面里出现一次而且短期也没有复用迹象就可以先留在页面内部。这点非常重要。因为不是所有东西都必须马上抽出来。四、页面组件和通用组件有什么区别这是本章最关键的区分之一。你可以先把它们理解成两类角色。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 classNamepost-card p classNamepost-card__meta {props.category} · {props.publishDate} /p h2 classNamepost-card__title Link href{props.href}{props.title}/Link /h2 p classNamepost-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 页面输入、提交与交互反馈的下一步。