type
Post
status
Published
date
Dec 20, 2025
slug
nextjs-003
summary
04 - Routing & Page Rendering - Deep Dive
tags
Next.js
category
编程学习
icon
password
😀

001 Module Introduction

002 Project Setup, Overview & An Exercise!

一、项目初始化与环境配置

  1. 项目获取与依赖安装
      • 课程提供演示项目,可从附件下载,解压后执行npm install安装所有依赖
      • 依赖安装完成后,通过npm run dev启动Next.js开发服务器,访问localhost:3000查看项目效果
  1. 初始项目结构解析(假设已掌握Next.js基础结构,重点说明核心文件/文件夹)
      • app文件夹:仅含icon.jpeg,Next.js会自动将其作为页面fav图标,无需额外配置
      • 全局CSS文件:包含课程所需基础样式,可自定义修改以调整应用外观
      • 布局文件:负责设置页面元数据(如标题、描述),并提供页面基础外壳(如公共头部/底部)
      • 首页page.js:结构简洁,无复杂逻辑,作为项目起始页面

二、核心实操任务(基础路由与组件开发)

1. 页面开发任务(2个核心页面)

页面路径
功能需求
关键技术点
/news
显示可点击的假新闻列表(无需真实数据),新闻项以链接形式呈现
1. Next.js文件路由规则(在app文件夹下创建news文件夹及page.js)<br>2. 使用next/link组件实现页面跳转
/news/[id]
新闻详情页,URL含新闻ID标识符(如/news/123
1. 动态路由配置(创建news/[id]文件夹及page.js)<br>2. 提取URL参数:通过useParams()(客户端组件)或params参数(服务器组件)获取id并在页面输出

2. 公共组件开发任务

  • 需求:创建独立的“主要标题组件”(Header),包含2个导航链接
  • 功能点
    • 链接1:指向首页(/
    • 链接2:指向新闻列表页(/news
  • 实现要点
    • 组件可放在components文件夹(需手动创建),便于复用
    • 使用next/link组件确保客户端导航,避免页面刷新

三、关键注意事项

  1. 组件区分:服务器组件默认无需'use client',仅当使用React hooks(如useState、useEffect)或浏览器API时,需声明为客户端组件
  1. 路由规则:App Router中,文件夹对应路由路径,page.js为路由入口,动态路由需用[参数名]命名文件夹
  1. 开发与生产差异:开发环境缓存默认关闭,生产环境需手动配置缓存策略,避免旧数据展示
  1. 依赖版本:确保React版本与Next.js 15兼容(推荐React 19),避免因版本不匹配导致的语法错误

003 Exercise Solution - Part 1

一、核心知识点:路由配置与页面创建

1. 静态路由创建(以/news路径为例)

  • 规则:Next.js App Router 采用“文件系统路由”,文件夹名称对应URL路径,需在文件夹内添加page.js(或jsx/ts/tsx)作为页面入口。
  • 步骤
      1. app目录下新建news文件夹(对应URL:/news);
      1. news文件夹中创建page.js,导出函数组件作为页面内容,示例代码:
    • 验证:启动项目后,访问http://localhost:3000/news,可看到“新闻页面”文本。

    2. 动态路由创建(以/news/[id]路径为例)

    • 场景:需实现URL参数动态变化(如新闻详情页/news/first-news/news/second-news)。
    • 规则:动态路径段用“方括号包裹占位符”(如[id]),占位符名称自定义(如[newsId]也可),同样需在动态文件夹内添加page.js
    • 步骤
        1. app/news目录下新建[id]文件夹(对应URL:/news/:id);
        1. [id]文件夹中创建page.js,示例代码:
      • 验证:访问http://localhost:3000/news/abc,可看到“新闻详细页面”文本,URL中abc即为动态参数id的值。

      二、页面导航:Next.js 推荐方案

      1. 避免使用原生<a>标签

      • 问题:原生<a>标签会导致页面全量刷新,破坏单页应用(SPA)的流畅性。
      • 替代方案:使用 Next.js 内置的Link组件,从next/link导入,确保导航在SPA流程内完成,无页面刷新。

      2. Link组件使用示例(新闻列表页添加导航)

      • 需求:在/news页面添加3个链接,分别指向/news/first-news/news/second-news/news/third-news
      • 代码实现
        • 效果:点击链接时,URL更新但页面不刷新,直接渲染对应动态路由页面。

        三、动态路由参数提取

        1. 参数传递规则

        • Next.js 会自动向动态路由的page.js组件传递params属性(字幕中误称“parents”),该属性是对象类型,键为动态占位符(如id),值为URL中对应参数。

        2. 提取id参数并展示

        • 需求:在新闻详情页(/news/[id])中显示当前URL的id值(如访问/news/second-news时,显示“新闻id:second-news”)。
        • 代码实现
          • 效果:访问/news/second-news时,页面显示“新闻id:second-news”,参数随URL动态变化。

          004 Exercise Solution - Part 2

          一、核心任务目标

          向 Next.js 项目添加主要标题组件,组件需包含两个关键链接:
          • 链接1:指向首页(路由路径为 /
          • 链接2:指向新闻页(路由路径为 /news
          • 组件定位:作为独立组件存在,需在所有页面内容上方显示,实现跨页面共享

          二、项目结构与组件存放策略

          1. 组件文件夹位置选择(灵活可选,无强制标准)

          存放位置
          具体路径示例
          优势
          应用内
          /app/components/
          与应用核心代码关联紧密,适合小型项目
          应用外(推荐)
          /components/(与 /app 同级)
          结构清晰,便于大型项目组件复用与维护
          • 结论:无最优方案,取决于个人/团队开发习惯,视频中采用“应用外同级文件夹”方案

          2. 关键文件创建

          • 组件文件:在 components/ 文件夹下新建导航栏组件文件(如 MainHeader.js
          • 核心功能:导出 MainHeader 组件函数,返回包含导航链接的 DOM 结构

          三、导航组件实现步骤

          1. 组件代码核心逻辑

          2. 组件导入方式(利用 Next.js 路径别名)

          • 路径别名规则:使用 @ 符号直接指向项目根目录,无需相对路径(如 ../
          • 导入代码示例:
            • 优势:简化导入路径,避免多层嵌套导致的路径错误

            四、布局(Layout)实现组件共享

            1. 布局核心作用

            • 解决问题:避免手动在每个页面组件中重复引入导航栏(低效且难维护)
            • 核心价值:为所有页面创建“内容外壳”,实现共享组件(如导航、页脚)的统一管理

            2. 根布局(Root Layout)操作

            • 根布局位置:/app/layout.js(Next.js 项目必有的核心文件,控制所有页面的公共结构)
            • 引入导航组件步骤:
                1. layout.js 中导入 MainHeader 组件
                1. body 标签内,将 {children}(页面动态内容)包裹在 MainHeader 下方
                1. 代码示例:

              3. 效果验证

              • 功能:保存后所有页面(包括首页、新闻页、详情页)顶部都会显示导航栏,点击链接可正常跳转
              • 样式:初始无样式,后续可通过 CSS 模块、Tailwind 等方式优化

              005 App Styling & Using Dummy Data - 应用样式优化与假数据使用

              一、应用样式优化(核心操作)

              1. 头部样式优化

              • 文件替换:获取更新后的main dash header.js文件,用其内容完全替换项目中原有同名文件,新文件通过新增标记和ID提升样式精细度,优化头部视觉效果(虽非最终完美版本,但为后续样式迭代打基础)。
              • 效果目标:使应用头部布局更规整,为后续整体样式统一做铺垫。

              2. 全局布局样式优化

              • 关键操作:在layout.js文件中,用带有id="page"<div>标签包裹“主要标题+子内容”组合。
              • 核心作用:通过该div的样式配置(如添加padding),让页面内容与边缘保持合理间距,提升整体美观度,且优化效果同步适用于新闻页面。

              3. 新闻页面链接样式优化

              • 类名添加:打开新闻页面对应的JS文件,在存储链接的无序列表(<ul>)内所有链接元素中,添加全局CSS已定义的新库存列表的道具类名。
              • 效果逻辑:借助预配置的CSS规则,改善链接默认外观(如调整颜色、间距、 hover 效果等),使新闻项视觉区分度更高。

              二、假数据应用(数据渲染流程)

              1. 假数据准备

              (1)假图片资源

              • 存储路径:项目公共文件夹(public)下的images/use子文件夹,内置用于项目演示的假图片,无需额外上传。

              (2)假新闻数据文件

              • 文件部署:将提供的假新闻.js文件复制到项目根目录(与appcomponents文件夹同级)。
              • 数据结构:文件导出含多个新闻项的数组,每个新闻项包含:
                • id:唯一标识(数字/字符串格式)
                • slug:URL友好型标识(替代id生成易读URL,如“2024-nextjs-update”)
                • 标题图像:对应假图片文件名(关联public/images/新闻路径下的图片)
                • 日期:新闻发布时间(如“2024-12-01”)
                • 占位内容:新闻正文文本(用于填充页面)

              2. 新闻页面数据渲染

              (1)数据导入

              • 在新闻页面JS文件顶部,通过import 占位新闻 from './假新闻.js'(路径需根据实际项目结构调整)导入假新闻数组。

              (2)动态生成JSX

              • 映射数据:通过占位新闻.map(新闻项 => { ... })遍历数组,为每个新闻项生成:
                  1. 新闻项.id的列表项(<li key={新闻项.id}>
                  1. 可点击链接(<a>):href用模板字符串动态构建,如/news/${新闻项.slug}(使用slug确保URL美观且SEO友好)
                  1. 新闻图片:<img src={/images/新闻/${新闻项.标题图像}} alt={新闻项.标题}(路径匹配公共文件夹结构,alt文本提升可访问性)
                  1. 新闻标题:用<span>标签展示新闻项.标题

              3. 新闻详情页数据匹配与渲染

              (1)识别当前新闻项

              • 数据导入:同新闻页面,导入假新闻.js文件。
              • 匹配逻辑:通过URL中的slug参数(如/news/2024-nextjs-update中的2024-nextjs-update),结合假新闻.find(项 => 项.slug === URL中的slug)找到当前需展示的新闻项。

              (2)页面内容渲染

              • <article class="news-详情">标签包裹所有内容(类名用于样式控制),内部依次渲染:
                  1. 新闻图片:<img src={/images/新闻/${新闻项.标题图像}} alt={新闻项.标题}
                  1. 新闻标题:<h1>{新闻项.标题}</h1>
                  1. 发布时间:<time datetime={新闻项.日期}>{新闻项.日期}</time>datetime属性符合语义化标准)
                  1. 新闻正文:<p>{新闻项.占位内容}</p>

              006 Handling Not Found Errors & Showing Not Found Pages - 处理“未找到页面”(404错误)

              一、核心目标

              解决用户访问不存在页面/资源(如无效路由、不存在的新闻文章)时的错误提示问题,通过自定义未找到页面提升用户体验,避免直接暴露运行时错误。

              二、关键实现方法

              1. 创建全局未找到页面(捕获全站404错误)

              • 文件要求:在项目app文件夹根级别创建not-found.js文件(Next.js 15 App Router约定的特殊文件名,不可自定义)。
              • 核心逻辑:文件内需导出一个组件函数,返回自定义错误提示内容(需保证样式适配项目),示例代码结构:
                • 生效范围:捕获整个网站所有未找到错误(如访问/abc/invalid-page等无效路由)。
                • 验证方式:保存文件后,在浏览器访问任意不存在的页面,即可看到上述自定义内容。

                2. 创建路由特定未找到页面(适配子路由场景)

                • 适用场景:针对特定子路由(如新闻详情页、商品详情页),需显示与该场景匹配的未找到提示(而非全局通用提示)。
                • 实现步骤
                    1. 复制根级别not-found.js文件,粘贴到目标子路由文件夹(如新闻相关的app/news文件夹);
                    1. 修改组件函数的文本内容,适配子路由场景,示例:
                  • 优先级规则:访问子路由下的无效路径(如/news/abc)时,Next.js会优先加载子路由文件夹下的not-found.js,而非根级别文件。

                  3. 主动触发未找到错误(解决动态路由“假404”问题)

                  • 问题背景:动态路由页面(如新闻详情页app/news/[slug].js)中,若根据URL的slug查询数据(如新闻文章)返回undefined(即数据不存在),Next.js不会自动触发404,而是会抛出运行时错误。
                  • 解决步骤
                      1. 导入触发函数:从next/navigation中导入notFound函数(Next.js 15提供的官方工具函数);
                      1. 添加数据检查逻辑:在动态路由页面中,查询数据后判断是否存在,若不存在则调用notFound()触发404,示例:
                    • 生效效果:访问/news/abc(不存在的新闻slug)时,不再抛出运行时错误,而是显示app/news/not-found.js定义的内容。

                    三、关键注意事项

                    1. 文件命名约束:未找到页面必须命名为not-found.js,不可自定义(Next.js App Router的约定);
                    1. 路由优先级:子路由下的not-found.js优先级高于根级别,即“就近匹配”原则;
                    1. 动态路由必做检查:动态路由页面(含[param]的路由)必须添加数据存在性检查并调用notFound(),否则会出现运行时错误;
                    1. 样式一致性:全局和路由特定的未找到页面需保持基础样式统一,避免用户体验割裂。

                    007 Setting Up & Using Parallel Routes

                    一、平行路由基础概念

                    1. 定义:Next.js 的核心路由功能,支持在同一页面中同时渲染多个独立路由的内容(不同路径的页面可共存显示),适用于侧边栏、仪表盘分栏等场景(如案例中“新闻归档+最新新闻”双区域布局)。
                    1. 核心价值:无需通过组件嵌套实现多区域展示,直接通过路由配置分离内容,提升代码可维护性。

                    二、平行路由配置步骤(关键操作)

                    1. 目录结构约定(必须遵循)

                    • 核心规则:平行路由文件夹需以 @ 符号开头(Next.js 识别标识),名称可自定义(需与布局组件中属性名对应)。
                    • 案例目录结构(以 /archive 路径为例):

                      2. 编写平行路由页面(page.js)

                      • 每个 @xxx 文件夹下的 page.js 对应一个平行区域的内容,与普通页面编写逻辑一致。
                      • 案例代码
                        • @archive/page.js(归档页面):
                          • @latest/page.js(最新新闻页面):

                          3. 配置布局文件(layout.js)—— 实现多路由同时显示

                          • 核心差异:普通布局仅通过 children 属性渲染单个页面,平行路由布局需通过与平行路由同名的属性(如 archivelatest)获取各区域内容。
                          • 案例代码
                            • 访问效果:启动项目后访问 localhost:3000/archive,可同时看到“档案页”和“最新新闻页”的内容(默认上下排列,可通过 CSS 调整布局)。

                            三、后续扩展方向

                            1. 功能增强
                                • @archive 区域扩展为“按年份+月份筛选”的新闻归档列表,支持导航交互。
                                • 保持 @latest 区域独立,始终显示最新新闻,不随归档筛选结果变化。
                            1. 样式优化:通过 CSS(如 Flex/Grid)调整两个平行区域的布局(如左右分栏),提升页面美观度。

                            008 Working with Parallel Routes & Nested Routes - 并行路由与嵌套路由

                            一、核心需求与路由特性定位

                            1. 并行路由的适用场景:单页显示多段内容可通过单页面实现,无需独立路由;但需实现“档案页按年份筛选新闻”这类需URL关联筛选条件、且页面多区块独立渲染的功能时,必须依赖并行路由。
                            1. 嵌套路由的作用:在档案页(/archive)下添加动态路由段(如[year]),将用户选择的年份作为URL占位符(如/archive/2024),实现“URL与筛选条件绑定”,便于定位和分享特定年份的新闻内容。

                            二、项目结构与辅助文件配置

                            1. 辅助文件(工具函数)设计

                            • 用途:封装假新闻数据处理逻辑,避免代码冗余,核心功能包括:
                              • 获取所有新闻包含的年份(按顺序排序);
                              • 筛选指定年份的新闻;
                              • 获取最新新闻列表。
                            • 存放路径:新建lib文件夹(与components同级),创建news.js文件存储上述工具函数(非组件类代码,单独归类便于维护)。

                            2. 路由文件夹结构(关键)

                            三、核心功能实现步骤

                            1. 档案页年份导航(archive/page.js

                            • 替换页面结构:用<header>标签(用于样式化)替换原<h1>,内部添加<nav>+<ul>实现年份导航。
                            • 动态渲染年份链接
                                1. 导入lib/news.js的“获取可用年份”函数,得到年份数组(如[2022,2023,2024]);
                                1. 通过map遍历年份数组,生成<li>+<Link>(从next/link导入);
                                1. 链接路径动态拼接:/archive/${year},文本显示年份,示例代码:

                              2. 新闻列表组件复用(components/list.js

                              • 设计目的:主新闻页、档案筛选页均需显示新闻列表,封装为组件减少重复代码。
                              • 核心逻辑
                                  1. 接收news props(需筛选后的新闻数组);
                                  1. 渲染<ul>+<li>,每个列表项通过<Link>链接到新闻详情(需导入next/link,避免 reload 错误);
                                  1. 示例代码:

                                3. 动态年份新闻筛选(archive/[year]/page.js

                                • 获取年份参数:通过Next.js自动注入的params prop获取动态路由值,即params.year[year]为路由占位符,故参数名是year)。
                                • 筛选并渲染新闻
                                    1. 导入lib/news.js的“筛选指定年份新闻”函数;
                                    1. 调用函数传入params.year,得到该年份新闻;
                                    1. 引入NewsList组件,传递筛选后的news props,示例代码:

                                  4. 解决并行路由“未找到页面”错误

                                  • 错误原因:并行路由(如latest)与archive/[year]共享同一页面,latest路由默认不支持/archive/[year]这类嵌套路径,导致其中一个并行区块无匹配内容,触发404。
                                  • 解决方案:添加default.js文件
                                      1. latest文件夹下创建default.js(文件名固定,Next.js识别为并行路由的 fallback 内容);
                                      1. 内容与“最新新闻页”一致:调用lib/news.js的“获取最新新闻”函数,渲染NewsList组件;
                                      1. 效果:无论archive路由下嵌套路径如何变化(如/archive/2024),latest区块始终显示最新新闻,不再触发404。

                                  四、关键注意事项

                                  1. 组件导出要求:动态路由(如[year]/page.js)必须默认导出React组件,否则点击年份会触发“非组件”错误。
                                  1. 开发服务器重启:修改路由结构(如添加default.js)后,若出现错误需重启开发服务器,避免Next.js缓存旧路由配置。
                                  1. 并行路由核心逻辑:同一页面的多个并行路由(如archivelatest)相互独立,需确保所有并行路由都支持当前URL路径(或通过default.js提供 fallback),否则会出现区块缺失。

                                  五、最终效果与特性总结

                                  1. 功能验证:访问/archive,页面上方显示年份导航,下方显示最新新闻;点击年份(如2024),URL变为/archive/2024,上方显示2024年新闻,下方最新新闻保持不变,实现“同一页面双路由独立渲染”。
                                  1. 特性定位:并行路由非高频刚需特性,但适用于“多区块独立控制、URL关联部分区块状态”的场景(如后台管理页的“列表+详情”、内容页的“筛选结果+推荐内容”),是Next.js路由系统的重要补充。

                                  009 Configuring Catch-All Routes

                                  一、核心问题:路由层级不足的痛点

                                  在示例应用中,选择年份后出现以下问题,需通过通配符路由解决:
                                  1. 功能受限:仅能查看选中年份的文章,无法进一步选择“月份”筛选更细粒度的内容
                                  1. 导航消失:进入年份页面后,年份导航栏消失,用户无法返回或切换其他年份
                                  1. 路由刚性:标准动态路由(如[year])仅能捕获单个路径分段,无法支持多层级(如“年份/月份”)的路径匹配

                                  二、解决方案:通配符路由核心配置

                                  1. 通配符路由的定义规则

                                  • 语法格式:通过文件夹命名实现,将标准动态路由的[标识符]改为[...标识符](方括号内添加“三个点+自定义标识符”)
                                  • 示例:将原动态路由文件夹[year]重命名为[...filter],其中“filter”为自定义标识符(可根据业务场景命名,如“params”“pathSegments”等)

                                  2. 核心作用

                                  • 捕获多段路径:可捕获目标路由(如/archive)后的所有路径分段,无论分段数量(如/archive/2024“1段”、/archive/2024/03“2段”均能匹配)
                                  • 路径数据格式:自定义标识符(如“filter”)会作为数组返回,数组元素为匹配的路径分段。例如:
                                    • 访问/archivefilterundefined(无路径分段)
                                    • 访问/archive/2024filter["2024"](1个分段)
                                    • 访问/archive/2024/03filter["2024", "03"](2个分段)

                                  三、实操步骤:从配置到验证

                                  1. 路由文件改造

                                  1. 重命名动态路由文件夹:找到目标路由(如/archive下的动态路由文件夹),将[year]改为[...filter]
                                  1. 调整页面组件代码
                                      • 重命名接收动态参数的常量:从const { year } = params改为const { filter } = params
                                      • 添加测试日志:console.log(filter),用于后续验证路径捕获结果
                                      • 临时注释无效代码:若原代码依赖year参数(如年份筛选逻辑),先注释以避免报错,返回占位内容(如<p>Loading filtered content...</p>

                                  2. 解决路由冲突

                                  • 冲突原因:若/archive目录下同时存在默认页面(如page.js)和通配符路由文件夹([...filter]),Next.js 会因“路由匹配歧义”报错
                                  • 解决方案
                                      1. 删除/archive下的默认page.js(避免与通配符路由竞争匹配)
                                      1. 将原默认页面的内容(如头部导航、文章列表组件)迁移到[...filter]/page.js中,确保仅通配符路由页面加载

                                  3. 测试与验证

                                  1. 重启开发服务器:保存修改后重启,确保无路由冲突报错
                                  1. 多场景验证
                                      • 访问/archive:页面正常显示列表,终端日志输出filter: undefined
                                      • 访问/archive/2024:终端日志输出filter: ["2024"],证明单段路径捕获成功
                                      • 访问/archive/2024/03:终端日志输出filter: ["2024", "03"],证明多段路径捕获成功
                                  1. 后续扩展:基于filter数组数据开发筛选逻辑(如根据filter[0](年份)、filter[1](月份)过滤文章)

                                  四、关键注意事项

                                  1. 路由优先级:通配符路由优先级低于具体路由(如/archive/2024若存在单独的2024/page.js,会优先匹配该页面,而非通配符路由)
                                  1. 参数类型filter数组元素均为字符串类型,若需数字类型(如年份、月份),需手动转换(如const year = Number(filter[0])
                                  1. 边界处理:需考虑filterundefined的场景(即访问根路由/archive),避免因“数组越界”导致报错

                                  010 Catch-All Fallback Routes & Dealing With Multiple Path Segments - 路由与数据处理

                                  一、Catch-All Fallback Routes 核心应用

                                  1. 多路径段参数提取逻辑

                                  • 参数获取与容错处理:通过筛选器(filter)提取路径中的年份、月份参数,用filter?.[0](可选链+数组索引)简化判断,未定义时自动存储为undefined,避免代码报错
                                    • 年份参数:const selectedYear = filter?.[0]
                                    • 月份参数:const selectedMonth = filter?.[1]
                                    • 替代方案(三元表达式):const selectedYear = filter ? filter[0] : undefined(代码冗长,不推荐)
                                  • 参数类型明确:已知filter定义时为数组类型,可直接通过索引访问,无需额外类型断言

                                  2. 动态路由路径配置

                                  • 路径规则设计:基于“档案/年份/月份”层级结构,实现不同筛选维度的路由匹配
                                    • 仅年份筛选:路径为/档案/[年份](如/档案/2024
                                    • 年份+月份筛选:路径为/档案/[年份]/[月份](如/档案/2024/1
                                  • 动态链接生成:通过条件判断动态设置Link组件的href属性

                                    二、数据筛选与页面渲染

                                    1. 新闻数据按需获取

                                    • 数据获取函数调用:根据筛选参数调用对应工具函数,实现精准数据筛选
                                      • 仅年份:getNewsByYear(selectedYear)(需传入年份参数)
                                      • 年份+月份:getNewsByYearAndMonth(selectedYear, selectedMonth)(需传入两个参数)
                                    • 数据有效性校验:通过if (news && news.length > 0)确保数据为非空数组,避免渲染空列表

                                    2. 备用内容与条件渲染

                                    • 默认备用内容:初始定义content = <p>未找到所选时间段的内容</p>,作为无数据时的兜底显示
                                    • JSX根元素约束:多个JSX元素需用<>(片段)或容器标签包裹,避免语法错误

                                      三、导航与路由状态管理

                                      1. 导航显示逻辑控制

                                      • 导航动态隐藏:当同时选中年份和月份(精确到月份筛选)时,将导航链接数组设为空links = [],隐藏导航栏,避免冗余交互
                                      • 导航状态恢复:返回上级页面(如从“年份+月份”回到“仅年份”)时,自动重新加载对应层级的导航选项(年份或月份)

                                      2. 非支持路径处理

                                      • 默认备用行为:当路径包含多余或不支持的段(如/档案/2024/1/abc),因未匹配对应数据逻辑,会自动显示“未找到内容”的备用文本
                                      • 自定义扩展方向:可通过添加路径校验逻辑(如判断路径段数量、格式),修改默认行为(如跳转404页面)

                                      四、关键工具函数与依赖

                                      工具函数
                                      作用
                                      所需参数
                                      getNewsByYear
                                      获取指定年份新闻
                                      selectedYear
                                      getNewsByYearAndMonth
                                      获取指定年份+月份新闻
                                      selectedYearselectedMonth
                                      getAvailableMonths
                                      获取指定年份下的可用月份列表
                                      selectedYear

                                      五、核心注意事项

                                      1. 参数容错:始终用可选链(?.)处理路径参数,避免因参数缺失导致的运行时错误
                                      1. 数据校验:渲染列表前必须校验数据存在性和数组长度,提升用户体验
                                      1. JSX语法约束:严格遵守“单个根元素”规则,使用片段或容器标签包裹多元素
                                      1. 路由一致性:确保Linkhref路径与数据筛选逻辑匹配,避免“路径正确但数据不显示”的问题

                                      011 Throwing (Route-related) Errors - 路由相关错误处理

                                      一、核心问题背景

                                      在基于Next.js 15的项目中,当用户在URL中输入无效路由内容(如过多路径段、不存在的年份/月份参数)时,默认仅显示回退文本,无法明确提示“错误”状态,需通过代码优化实现路由错误的精准捕获与反馈。

                                      二、关键技术点与操作步骤

                                      1. 错误触发条件设计(双重校验逻辑)

                                      需在页面JS文件中,返回JSX内容前添加if判断,满足任一条件即抛出错误,核心逻辑如下:
                                      校验类型
                                      触发条件
                                      实现方式
                                      年份校验
                                      存在“选定年份”,且该年份不在“可用新闻年份数组”中
                                      使用数组!includes()方法,否定“可用年份包含选定年份”的结果
                                      月份校验
                                      存在“选定月份”,且该月份不在“对应选定年份的可用新闻月份数组”中
                                      通过逻辑或(`

                                      2. 类型不匹配问题解决方案

                                      • 问题根源:年份/月份工具函数返回数字类型,但从URL路径提取的“选定年份/月份”为字符串类型,即使值相同,includes()判断也会返回false(如4 === "4"false)。
                                      • 解决方法:在进行校验前,将从URL提取的“选定年份”和“选定月份”强制转换为数字类型(如Number(selectedYear)),确保类型统一。

                                      3. 开发模式与生产需求差异

                                      • 开发模式表现:配置错误触发逻辑后,访问无效路由(如/2025/13,13为无效月份)会显示Next.js默认的“开发模式错误覆盖层”,包含错误堆栈等技术信息。
                                      • 生产需求:需替换默认错误覆盖层为自定义错误页面(如404页面、参数无效提示页),需额外添加错误处理逻辑(后续课程可能展开)。

                                      三、核心代码逻辑(简化示例)

                                      四、学习要点总结

                                      1. 路由错误处理需结合业务场景(如年份/月份筛选),明确“无效参数”的定义,避免误判;
                                      1. 处理URL参数时,必须注意类型一致性(字符串→数字转换是常见坑点);
                                      1. 开发模式的默认错误提示仅用于调试,生产环境需自定义友好的错误页面,提升用户体验;
                                      1. 错误触发逻辑需覆盖所有可能的无效场景(如本文中“年份+月份”双重校验),避免遗漏。

                                      012 Handling Errors With Error Pages

                                      一、核心目标

                                      替换默认开发模式错误覆盖层,用自定义错误回退内容处理服务器端与客户端的错误,确保用户体验一致性。

                                      二、关键实现方式:特殊错误文件(error.js)

                                      1. 文件特性
                                          • 功能类比 not-found.js(404页面),属于Next.js约定式特殊文件。
                                          • 放置位置灵活:可在项目任意目录或特定页面同级目录,仅作用于当前目录及嵌套页面的错误处理。
                                          • 触发逻辑:当对应页面或嵌套页面发生错误时,自动渲染 error.js 中的组件。
                                      1. 基础代码结构

                                        三、核心规则:错误回退必须是客户端组件

                                        1. 强制要求
                                            • 必须在 error.js 文件顶部添加 'use client' 声明,否则无法生效。
                                        1. 底层原因
                                          1. 组件类型
                                            运行环境
                                            错误处理适配性
                                            客户端组件
                                            服务器+客户端
                                            支持两端错误捕获(推荐)
                                            未声明的服务器组件
                                            仅服务器端
                                            无法捕获客户端错误(不适用)
                                            • 错误可能发生在两个阶段:
                                              • 服务器端:页面初始渲染时(如数据请求失败);
                                              • 客户端:页面加载后用户交互时(如动态操作触发异常)。
                                            • 客户端组件可覆盖两端场景,因此是唯一适配方案。

                                        四、关键Props:获取实际错误信息

                                        • Next.js 会自动向 Error 组件传递 error 对象(包含错误详情),可通过 error.message 输出具体错误原因,替代固定文本(如“无效路径”),便于调试和用户理解。

                                        五、效果与后续操作

                                        1. 配置后效果:保存 error.js 后,触发错误时会显示自定义错误页面,而非默认覆盖层。
                                        1. 用户体验保障:用户可通过页面交互(如返回按钮、导航链接)离开错误状态,继续使用应用。

                                        013 Server vs Client Components

                                        一、核心概念与本质差异

                                        对比维度
                                        服务器组件(Server Components)
                                        客户端组件(Client Components)
                                        执行位置
                                        仅在服务器执行,组件函数不在客户端运行
                                        服务器初始预渲染 + 客户端(浏览器)可执行
                                        日志查看
                                        控制台日志仅出现在开发服务器终端
                                        日志可在浏览器开发者工具控制台查看
                                        适用场景
                                        无客户端交互需求的静态内容(如新闻列表、纯展示页面)
                                        需客户端交互/钩子的功能(如路由监听、表单交互)
                                        特殊规则
                                        next.js 中默认所有组件均为服务器组件
                                        error.js 定义的组件必须是客户端组件(需处理客户端代码错误)

                                        二、关键使用原则

                                        1. 默认优先用服务器组件
                                            • 无需客户端交互时,不主动将组件转为客户端组件
                                            • 优势:减少客户端代码加载量,降低浏览器负担,提升页面渲染效率
                                        1. 客户端组件的“必要场景”
                                            • 需使用 React 钩子(如 usePathname useState useEffect)时
                                            • 需处理客户端事件(如点击、输入、路由切换监听)时
                                            • 需渲染动态交互内容(如高亮当前导航链接、表单提交)时

                                        三、实践案例:导航链接高亮功能

                                        1. 需求背景

                                        给页面导航链接添加“当前路径高亮”效果,需判断当前 URL 路径是否匹配链接地址

                                        2. 技术关键点

                                        • 需使用 usePathname 钩子(从 next/navigation 导入)获取当前路径
                                        • usePathname 仅支持在客户端组件中使用,需手动添加 use client 指令

                                        3. 优化方案:最小化客户端组件

                                        • 问题:直接给整个头部组件(Header)加 use client 会导致大量静态内容被标记为客户端组件,浪费资源
                                        • 解决方案:拆分独立小型客户端组件
                                            1. 创建 NavLink.js 组件,仅包含链接高亮逻辑
                                            1. NavLink.js 顶部添加 use client 指令,导入 usePathname
                                            1. 通过 props 接收 href children 等参数,实现组件复用
                                            1. 主头部组件(Header)保持为服务器组件,引用 NavLink 组件

                                        4. 核心代码逻辑(简化版)

                                        014 Nested Routes Inside Dynamic Route - 动态路由内嵌套路由

                                        一、前置基础回顾

                                        • 核心概念:服务器端组件与客户端组件是Next.js开发的重要基础,二者使用难度低,但需明确其差异与适用场景,为后续路由功能学习奠定基础。
                                        • 学习衔接:掌握组件概念后,可深入探索Next.js路由特性,本次重点为“动态路由内的嵌套路由”,后续将进一步学习“拦截路由”。

                                        二、动态路由内嵌套路由核心实现(以新闻图片全屏功能为例)

                                        1. 需求场景

                                        实现新闻详情页中图片的点击交互,点击后跳转至独立页面,以全屏形式展示该新闻对应的图片。

                                        2. 文件结构配置

                                        • 在动态路由文件夹(如[slug],用于匹配新闻slug)内部,新建嵌套路由文件夹(名称自定义,示例为image)。
                                        • image文件夹中创建page.js文件,导出组件函数(命名为“ImagePage”),作为全屏图片展示页面的入口。

                                        3. 组件逻辑实现(image/page.js

                                        (1)获取动态参数

                                        • 通过组件接收的props提取params属性(或parents属性,视路由层级而定),从中获取动态路由的slug参数(因嵌套路由会继承父级动态路由的参数)。
                                        • 示例:const { slug } = params;(类似动态路由页面直接获取slug的逻辑)。

                                        (2)数据处理与异常控制

                                        • 复制动态新闻详情页的逻辑,包括“新闻项查找”与“未找到页面”处理:
                                          • 导入假新闻数据(如fakeNews),根据slug匹配当前新闻项。
                                          • next/navigation导入NotFound组件,若未匹配到新闻项,返回<NotFound />,确保路由异常时的用户体验。

                                        (3)动态渲染图片

                                        • 构建图片容器:添加full-screen-image类名的div作为全屏图片容器。
                                        • 动态设置图片源:图片存储路径为public/news/[图片名],其中图片名从匹配到的新闻项newsItem.image属性获取,示例:

                                          4. 跳转链接配置(新闻详情页)

                                          • 在动态新闻详情页([slug]/page.js)中,用next/linkLink组件包裹新闻图片,配置跳转路径:
                                            • 路径格式:/news/${newsItem.slug}/image(对应“新闻根路由/动态slug/嵌套image路由”的文件结构)。
                                            • 示例:

                                            三、关键区分与后续方向

                                            • 嵌套路由特性:动态路由内的嵌套路由是实用功能(开发中频繁用到),但本质是基于文件系统的路由层级扩展,并非“拦截路由”。
                                            • 后续学习:本次仅完成嵌套路由实现,后续将探索“拦截路由”功能(一种特殊的路由拦截与展示机制)。

                                            015 Intercepting Navigation & Using Interception Routes - 拦截路由(Interception Routes)

                                            一、核心概念

                                            1. 定义:拦截路由是Next.js 15中一种根据导航方式动态切换页面内容的路由机制,针对相同URL路径,会依据用户“如何到达该路径”显示不同页面
                                            1. 核心逻辑:仅拦截“页面内部链接导航”(单页应用模式下的跳转),对“外部链接进入、手动输入URL、页面刷新”这三类场景不拦截,实现“同路径不同内容”的差异化展示

                                            二、配置步骤(关键操作)

                                            1. 文件夹命名规则(核心)

                                            • 结构要求:创建与“目标拦截页面”同级的文件夹(非强制,但推荐,便于管理)
                                            • 命名格式(路径标识)目标路径名,例如要拦截image路由:
                                              • 同文件夹拦截:命名为(.)image(括号内的.代表当前文件夹,类似导入路径的./
                                              • 嵌套路径上一层拦截:命名为(..)image(括号内的..代表上一级文件夹,类似导入路径的../
                                              • 多文件夹段:需按层级添加..,具体可参考Next.js官方文档
                                            • 注意:括号为普通圆括号,非方括号或其他符号

                                            2. 页面文件创建

                                            • 在配置好的拦截路由文件夹中,添加page.js文件(Next.js App Router默认页面文件)
                                            • 在该文件中定义“拦截状态下的页面内容”,示例:复制原image页面代码,新增<h2>被拦截</h2>标识,用于区分拦截/非拦截状态

                                            三、效果验证(核心差异)

                                            导航方式
                                            页面显示效果
                                            加载文件
                                            页面内部链接跳转(如从新闻页点击图片)
                                            显示拦截页面(含“被拦截”标识)
                                            拦截路由文件夹下的page.js
                                            外部链接进入、手动输入URL、页面刷新
                                            显示原页面(无“被拦截”标识)
                                            image路由下的page.js

                                            四、应用场景(重点用法)

                                            1. 单独使用:实现基础的“导航方式差异化展示”,如内部跳转显示简化版页面,外部进入显示完整页面
                                            1. 与并行路由(Parallel Routes)结合(推荐核心场景):
                                                • 内部导航拦截时:在模态框(Modal)中显示内容,提升用户体验
                                                • 外部进入/刷新时:以全屏页面显示内容,保证页面完整性

                                            016 Combining Parallel & Intercepting Routes - 并行路由与拦截路由结合使用

                                            一、核心目标

                                            在Next.js 15中,通过结合并行路由(Parallel Routes)拦截路由(Intercepting Routes) ,实现“模态框覆盖层”功能——点击页面元素时以模态框形式展示内容,且背景保留原页面内容,而非跳转至全新全屏页面。

                                            二、关键步骤与技术点

                                            1. 基础:为拦截路由添加模态框结构

                                            • 核心操作:在拦截路由对应的JS文件中,构建模态框基础DOM结构
                                              • 创建div并添加类名modal backdrop,作为模态框背景层
                                              • 将模态框核心内容包裹在“对话容器”中,添加模态类名与open属性(控制显示状态)
                                            • 初始效果
                                              • 直接刷新页面:模态框页面仍为全屏显示
                                              • 点击触发进入:页面以模态框形式展示,但背景无内容(因模态框页面仍占据全部布局空间)

                                            2. 关键:用并行路由实现“覆盖层”效果

                                            (1)并行路由配置逻辑

                                            • 目标:让“原页面内容”与“模态框内容”在同一页面并行渲染,实现覆盖层效果
                                            • 文件结构设计
                                                1. 在父路由目录下,创建两个并行路由文件夹(兄弟关系):
                                                    • 模态:存放拦截路由对应的模态框组件
                                                    • 默认/详细信息:存放原页面(如新闻详情页)组件(可选,也可通过默认children属性替代)
                                                1. 父布局JS文件(位于并行路由文件夹上层):
                                                    • 接收children prop:渲染原页面内容(如新闻详情)
                                                    • 接收modal prop(因并行路由标识符设为“模态”):渲染模态框内容
                                                    • 渲染顺序:将modal内容输出在children上方,实现模态框覆盖原页面

                                            (2)路径规则特殊说明

                                            • 并行路由文件夹(如模态归档)不会影响URL路径,Next.js仅将其作为“组织文件的特殊目录”,忽略其在URL中的映射
                                            • 拦截路由的路径描述(如/(...拦截路由名))无需修改,即使移动到并行路由子文件夹中,仍保持原路径逻辑

                                            3. 避坑:解决“无内容时的报错”

                                            问题场景

                                            当进入原页面(如/news/[slug]新闻详情页),未触发拦截路由时,模态并行路由无内容可渲染,Next.js会因“该路径无组件”报错。

                                            解决方案

                                            模态并行路由文件夹中,添加默认组件文件(如default.js):
                                            • 导出一个简单组件,直接返回null
                                            • 作用:明确告知Next.js“该并行路由此时无需渲染内容”,避免报错

                                            三、最终效果与应用场景

                                            1. 实现效果

                                            • 触发拦截路由(如点击新闻详情页中的图片):模态框以覆盖层形式打开,背景保留原新闻详情页内容
                                            • 未触发拦截路由:仅显示原页面内容,模态并行路由因默认组件返回null而不渲染

                                            2. 应用场景

                                            适用于需要“在当前页面之上临时展示内容”的场景,如:
                                            • 图片预览模态框
                                            • 临时表单弹窗
                                            • 详情快速查看窗口

                                            017 Replace page.js with default.js

                                            You might be getting an error when trying to refresh the image detail route (/news/<some-news-identifier>/image).尝试刷新图片详情路由(/news/<some-news-identifier>/image)时,你可能会遇到错误。
                                            In that case, rename news/[slug]/@modal/page.js to default.js.在这种情况下,请将news/[slug]/@modal/page.js重命名为default.js
                                            notion image
                                            @modal 文件夹中创建default.js 文件:
                                            这个问题的根本原因是 Next.js 并行路由的工作方式:
                                            1. 当你从新闻详情页点击图片链接时,拦截路由 @modal/(.)image 会被触发,在模态框中显示图片,而不会导航到新页面。
                                            1. 但是当你直接访问或刷新 /news/[slug]/image URL 时,Next.js 需要渲染所有插槽,包括 @modal 插槽。
                                            1. 由于没有为 @modal 插槽定义默认组件(default.js),Next.js 不知道该渲染什么,因此回退到最近的 NotFound 边界,导致 404 错误。
                                            通过创建一个返回 nulldefault.js 文件,我们告诉 Next.js 在没有特定模态内容时不要渲染任何东西,这样就能避免 404 错误,让页面正常显示图片内容。

                                            018 Navigating Programmatically - 程序化导航

                                            一、核心功能需求与实现目标

                                            • 需求场景:点击模态框背景幕布,返回之前访问的页面(如从列表页进入的详情页)
                                            • 导航触发方式:通过代码逻辑触发页面导航,而非用户点击链接或浏览器返回按钮

                                            二、关键技术与实现步骤

                                            1. 路由钩子导入与使用

                                            • 导入路径:必须从 next/navigation 导入路由钩子(不可使用其他包)
                                            • 核心对象:通过钩子获取 router 对象,包含多种程序化导航方法
                                              • push():将新页面推入路由堆栈(新增历史记录)
                                              • refresh():手动刷新当前页面
                                              • back():返回上一页(核心需求对应方法,点击背景幕布时触发)

                                            2. 事件绑定注意事项

                                            • 正确绑定方式:在 onClick 中直接指向 router.back(无需加括号 ()),避免立即执行

                                              3. 客户端组件限制

                                              • 使用范围:路由钩子仅支持在客户端组件中使用
                                              • 启用方式:需在文件顶部添加 'use client' 指令声明客户端组件

                                              三、功能验证与效果

                                              • 操作流程:刷新页面进入详情页 → 点击模态窗口打开 → 点击背景幕布
                                              • 预期结果:模态窗口关闭,页面导航回上一页面,地址栏路径同步更新
                                               
                                              🗒️
                                              1. 异步客户端组件 :在 Next.js 中,客户端组件(使用 'use client' 指令)不能是异步函数。只有服务端组件可以是异步的。
                                              1. 解决方案 :
                                              • 移除了 async 关键字
                                              • 使用 useEffect 钩子来处理异步操作
                                              • 添加了 useState 来管理新闻项数据和加载状态
                                              • 在 useEffect 中处理异步参数解析和数据获取
                                              1. 改进点 :
                                              • 添加了加载状态显示
                                              • 增加了错误处理
                                              • 保持了原有的功能不变
                                               

                                              客户端组件不能是异步的主要原因是 React 的渲染模型和设计哲学:

                                              1. React 渲染机制

                                              React 组件的渲染必须是同步且可预测的。React 需要能够:
                                              • 立即计算出组件的 UI 输出
                                              • 跟踪状态变化和依赖关系
                                              • 在状态变化时重新渲染组件
                                              异步组件会破坏这种同步渲染模型,因为 React 无法知道异步操作何时完成。

                                              2. 客户端 vs 服务端组件的区别

                                              服务端组件(Server Components):
                                              • 在服务器上运行
                                              • 可以是异步的,因为它们直接访问数据源
                                              • 渲染完成后发送 HTML 到客户端
                                              • 不参与客户端的交互式渲染
                                              客户端组件(Client Components):
                                              • 在浏览器中运行
                                              • 必须是同步的,因为它们参与 React 的交互式渲染循环
                                              • 使用 hooks(如 useState, useEffect)处理状态和副作用

                                              3. Next.js 的设计决策

                                              Next.js 15 中的这个限制是为了:
                                              • 保持 React 组件的渲染可预测性
                                              • 防止渲染过程中的不确定性
                                              • 确保组件生命周期的一致性

                                              4. 正确的处理方式

                                              在客户端组件中处理异步操作的标准方法是:
                                              这种模式将异步操作从组件渲染过程中分离出来,放入副作用钩子中,保持了组件渲染的同步性。

                                              019 Defining the Base HTML Document

                                              Currently, this project has a small bug / issue - the root HTML document is re-defined for every route. The fix is to  define the base HTML document only once in a layout.js file inside the root folder path.目前,该项目存在一个小bug/问题——每个路由都会重新定义根HTML文档。解决方法是在根文件夹路径下的layout.js文件中仅定义一次基础HTML文档。
                                              Create an app/layout.js file with the following content:创建一个app/layout.js文件,内容如下:
                                              When following along with the next lecture, you'll also need to tweak the app/(content)/layout.js and app/(marketing)/layout.js files (which are created in the next lecture).在学习下一节课时,你还需要调整app/(content)/layout.jsapp/(marketing)/layout.js文件(这些文件将在下一节课中创建)。
                                              app/(content)/layout.js
                                              (created in next lecture, adjust it after watching the next lecture)(将在下一讲中创建,观看下一讲后进行调整)
                                              app/(marketing)/layout.js
                                              (created in next lecture, adjust it after watching the next lecture)(将在下一讲中创建,观看下一讲后进行调整)

                                              020 Using & Understanding Route Groups - 路由组(Route Groups)

                                              一、核心需求背景

                                              在Next.js应用开发中,默认根布局会作用于所有页面(如统一导航栏),但实际场景中存在差异化布局需求:网站起始页(着陆页)常需与其他功能页面(如新闻、归档)使用不同布局(例:起始页无导航,功能页显示导航),路由组(Route Groups)是解决该问题的关键特性。

                                              二、路由组核心概念

                                              1. 定义:Next.js App Router中的布局隔离工具,通过特定文件夹命名规则,为一组路由配置独立布局,且不影响URL路径。
                                              1. 关键特征
                                                  • 文件夹命名格式:用()包裹自定义名称(例:(content)(marketing)),括号内名称仅作标识,不参与URL生成。
                                                  • 作用范围:可在app文件夹顶级目录或嵌套路由中创建,组内路由共享该组专属布局。
                                                  • 与普通路由文件夹区别:普通文件夹(如news)会生成URL路径(例:/news),路由组文件夹不添加任何URL片段。

                                              三、实操步骤(以“起始页与功能页分布局”为例)

                                              1. 创建路由组文件夹

                                              app文件夹下新建两个路由组文件夹:
                                              • (content):存放应用核心功能路由(如newsarchive),对应“带导航”的布局。
                                              • (marketing):存放营销/着陆页路由(如起始页page.js),对应“无导航”的布局。

                                              2. 迁移路由与配置布局

                                              操作对象
                                              具体步骤
                                              功能路由(newsarchive
                                              1. 将原有newsarchive文件夹及嵌套路由,移动到(content)文件夹内;<br>2. 将原根布局文件(layout.js)复制到(content)文件夹,保留导航相关代码(如<MainNav>),并调整全局CSS导入路径(因在子文件夹,需改为../globals.css)。
                                              起始页路由(page.js
                                              1. 将原起始页page.js移动到(marketing)文件夹内;<br>2. 复制(content)/layout.js(marketing)文件夹,删除导航相关代码(如<MainNav>、导航样式div),同样调整全局CSS导入路径。

                                              3. 处理特殊页面(404未找到页)

                                              • 规则:设置路由组后,所有页面(包括not-found.js)必须归入某一路由组,不可在app根目录单独存在。
                                              • 操作:将not-found.js移动到(content)文件夹,确保功能页场景下的404页面使用“带导航”布局。

                                              4. 验证效果

                                              • 访问起始页(URL:/):加载(marketing)/layout.js,无导航,符合预期。
                                              • 访问新闻页(URL:/news):加载(content)/layout.js,显示导航,符合预期。

                                              四、核心价值与应用场景

                                              1. 核心价值:实现“路由分组-布局绑定”,避免布局代码冗余,同时保持URL简洁。
                                              1. 典型应用场景
                                                  • 多模块隔离:如“用户中心模块”((user))与“公共模块”((public))分属不同路由组,使用不同布局。
                                                  • 营销页与功能页分离:如活动着陆页(无导航)与产品功能页(有导航)的布局隔离。
                                                  • 权限相关布局:如“登录页组”((auth),无侧边栏)与“登录后页组”((dashboard),有侧边栏)的区分。

                                              五、注意事项

                                              1. 布局文件路径:路由组内的layout.js仅对组内路由生效,若需全局共享基础样式(如重置样式),可在app/layout.js中保留公共样式导入,路由组布局通过childrenprop嵌套使用。
                                              1. CSS导入路径:路由组文件夹为子目录,需根据相对路径调整CSS导入(例:(content)/layout.js导入根目录globals.css时,路径为../globals.css)。
                                              1. 页面归属app根目录下不可保留除路由组、globals.cssfavicon.ico外的其他页面文件(如单独的page.jsnot-found.js),必须归入路由组。

                                              021 Building APIs with Route Handlers - 路由处理程序

                                              一、核心定义与定位

                                              • 本质:Next.js 中用于构建 API 类路由的特性,不渲染页面、无需布局,仅处理数据交互(非页面渲染场景)
                                              • 核心作用:实现后台数据操作,包括产生数据、存储数据、接收/返回请求等,支持与外部客户端(如移动应用、前端页面)通信
                                              • 与普通页面路由区别:不属于路由组,无需布局文件,不生成可视化页面,仅响应数据请求

                                              二、文件创建与命名规则

                                              配置项
                                              具体要求
                                              示例
                                              路径位置
                                              需放在路由组之外(避免继承不必要的布局)
                                              项目根目录下创建 api 文件夹(路径名称可自定义)
                                              核心文件
                                              必须命名为 route.js(Next.js 非保留名,专门用于路由处理程序)
                                              api/route.js
                                              导出函数
                                              函数名需与 HTTP 方法一致,支持 get、post、patch、put、delete 等
                                              导出 async function GET() {} 处理 GET 请求

                                              三、请求与响应处理

                                              1. 请求对象(Request)
                                                  • 由 Next.js 自动传递,包含请求方法、请求体、请求头、查询参数等信息
                                                  • 可提取关键数据:如从请求体中获取客户端提交的数据,用于数据库存储;从请求方法中判断请求类型
                                                  • 调试方式:在处理函数中打印请求对象,可在服务器端终端查看详细数据
                                              1. 响应对象(Response)
                                                  • 需手动构建并返回,基于浏览器和 Node.js 内置的 Response
                                                  • 支持响应类型:纯文本、JSON 数据(可使用 Response.json() 工具方法简化 JSON 响应)
                                                  • 示例代码:

                                                四、关键特性

                                                • 多请求类型支持:同一 route.js 文件中可导出多个不同 HTTP 方法的函数,处理同一路径的不同请求(如 GET 查数据、POST 存数据)
                                                • 请求触发方式:GET 请求可直接通过浏览器输入路径触发(如 http://localhost:3000/api);其他类型请求需通过前端代码(如 fetch、axios)或外部客户端发送
                                                • 无布局依赖:因不渲染页面,无需继承路由组的布局,独立于页面渲染流程

                                                五、应用场景与学习意义

                                                1. 核心应用场景
                                                    • 为 Next.js 应用对接外部客户端(如移动 App),提供数据接口
                                                    • 处理前端页面的后台数据交互(如表单提交、数据查询,不用于页面整体渲染)
                                                    • 实现数据存储、第三方 API 转发等服务器端操作
                                                1. 学习必要性
                                                    • 虽非所有 Next.js 项目必需,但是构建全栈应用的重要能力
                                                    • 拓展 Next.js 应用的适用范围,从单纯页面渲染延伸到数据服务提供

                                                六、使用注意事项

                                                • 若不需要处理某类 HTTP 请求(如 POST),可注释或删除对应导出函数,避免不必要的请求处理
                                                • 提取请求体数据时需注意数据验证,防止非法数据提交
                                                • 部署时需确保路由路径配置正确,避免与其他页面路由冲突
                                                🗒️

                                                Next.js 15 路由处理程序 vs 传统后端API:核心区别解析

                                                Next.js 15 的路由处理程序(Route Handlers)本质是前端框架内置的服务端数据交互层,与 Node.js/Java/PHP 等构建的传统后端API存在底层设计、部署形态、使用场景等多维度差异,以下是核心区别梳理:
                                                对比维度
                                                Next.js 15 路由处理程序
                                                传统后端API(如Express/Koa/Java Spring/PHP)
                                                核心定位
                                                前端框架的“内置服务端能力”,为Next.js应用提供数据接口,属于全栈框架的一部分,服务于前端页面/客户端的数据需求
                                                独立的“后端服务”,专注处理全系统的业务逻辑、数据存储、权限控制,是前后端分离架构的核心后端层
                                                技术栈依赖
                                                强绑定Next.js/React生态,仅支持JavaScript/TypeScript,复用前端项目的依赖、配置(如环境变量、TS配置)
                                                技术栈独立:可选择Node.js(Express)、Java、Python、PHP等,与前端技术栈解耦,可单独选型
                                                部署形态
                                                与Next.js前端应用同部署(如Vercel、Netlify、服务器部署Next.js项目),无需单独部署后端服务;支持边缘运行时(Edge Runtime),可部署在CDN边缘节点
                                                独立部署(如部署到服务器、容器、云函数),与前端应用分离,通常通过域名/端口独立访问(如api.xxx.com
                                                路由规则
                                                基于文件系统路由:route.js文件的存放路径即API路径(如app/api/user/route.js对应/api/user),无需手动配置路由映射
                                                需手动配置路由规则(如Express的app.get('/api/user', handler)、Spring的@RequestMapping),路由与文件路径无强关联
                                                运行环境
                                                支持两种运行时:<br>1. 节点运行时(Node.js Runtime):基于Node.js,可使用Node.js API;<br>2. 边缘运行时(Edge Runtime):轻量、跨平台,无Node.js内置模块(如fs),适合高频轻量请求
                                                依赖特定运行环境:<br>- Node.js系(Express/Koa):需Node.js运行时;<br>- Java系:需JVM;<br>- PHP:需PHP解释器+Nginx/Apache
                                                与前端的耦合度
                                                高度耦合:<br>1. 可直接复用前端的类型定义(TS)、工具函数;<br>2. 可直接访问Next.js的内置能力(如React Server Components、缓存、中间件);<br>3. 路径与前端路由统一管理,避免跨域(同域)
                                                低耦合:<br>1. 与前端完全分离,仅通过HTTP接口通信;<br>2. 需单独处理跨域(CORS)、接口鉴权、数据格式协商;<br>3. 前端需通过fetch/axios跨域请求,需处理请求头、状态码等
                                                业务能力边界
                                                适合轻量级数据交互:<br>- 前端页面的表单提交、数据查询;<br>- 第三方API转发、简单数据处理;<br>- 与Next.js缓存(如SWR/React Cache)联动;<br>不适合复杂业务:如分布式事务、高并发数据库操作、复杂权限体系
                                                适合全量后端业务:<br>- 复杂业务逻辑(如订单处理、支付流程);<br>- 分布式系统、微服务架构;<br>- 高并发、高可用设计(如负载均衡、数据库集群);<br>- 底层数据存储、权限中心、日志系统等
                                                开发与调试效率
                                                一站式开发:<br>- 前端开发者无需切换技术栈,用JS/TS即可开发;<br>- 与Next.js前端代码同仓库,调试时无需跨项目;<br>- 热更新、断点调试与前端统一
                                                跨栈开发:<br>- 需独立的后端开发团队、技术栈;<br>- 前后端分仓库,调试需联调(如接口文档、环境配置);<br>- 后端修改需单独重启服务,调试成本高
                                                性能与优化
                                                内置优化能力:<br>- 边缘运行时可就近响应请求(CDN边缘节点),降低延迟;<br>- 复用Next.js的缓存策略(如Data Cache、Full Route Cache);<br>- 支持流式响应(Streaming Response),适配React的流式渲染
                                                需手动优化:<br>- 需自行配置缓存(如Redis)、负载均衡、CDN;<br>- 流式响应、压缩等需手动实现;<br>- 性能优化依赖后端开发者的经验(如数据库索引、接口缓存)
                                                扩展性
                                                扩展性有限:<br>- 仅能基于Next.js生态扩展,无法对接非JS生态的中间件/插件;<br>- 不支持微服务拆分,适合单体全栈应用
                                                扩展性强:<br>- 可根据业务拆分微服务、接入各类中间件(如消息队列、分布式缓存);<br>- 支持多语言、多框架对接,适配复杂业务场景

                                                核心差异总结

                                                1. 设计初衷不同
                                                    • Next.js 路由处理程序:为了让前端开发者“无感知”地实现服务端数据交互,降低全栈开发门槛,核心服务于Next.js应用本身,是“前端框架的延伸”;
                                                    • 传统后端API:为了构建独立的、通用的后端服务,支撑全系统的业务逻辑,可对接多个前端(Web/APP/小程序),是“独立的服务层”。
                                                1. 适用场景不同
                                                    • 选路由处理程序:Next.js 单体全栈应用、轻量级数据接口(如表单提交、简单查询)、需要与React Server Components联动、追求开发效率;
                                                    • 选传统后端API:复杂业务逻辑(如支付、订单)、多前端对接、高并发/高可用要求、需要微服务架构、非JS技术栈选型。
                                                1. 开发体验不同
                                                    • 路由处理程序:前端开发者“一站式搞定”,无需跨栈,同仓库、同语言、同调试环境;
                                                    • 传统后端API:前后端分离,需联调、定义接口文档、处理跨域/鉴权,适合专业后端团队维护。

                                                补充:两者的融合使用

                                                实际项目中并非非此即彼:可基于Next.js路由处理程序做轻量接口层(如前端数据适配、缓存、第三方API转发),再对接传统后端API处理复杂业务(如数据库操作、权限校验),兼顾开发效率与业务复杂度。
                                                🗒️

                                                多个 route.js 文件

                                                Next.js 15 路由处理程序的核心设计就是基于文件系统的路由规则,多个 route.js 对应不同的 API 路径,是构建多接口的核心方式,以下是详细说明:

                                                一、多个 route.js 的存在形式:按路径分层

                                                每个 route.js 独立对应一个 API 路径,文件的存放路径决定了接口的访问地址,示例如下:
                                                文件路径
                                                对应的 API 访问路径
                                                功能说明
                                                app/api/user/route.js
                                                http://localhost:3000/api/user
                                                处理用户相关请求(如查用户、创建用户)
                                                app/api/post/route.js
                                                http://localhost:3000/api/post
                                                处理文章相关请求(如查文章、发布文章)
                                                app/api/order/route.js
                                                http://localhost:3000/api/order
                                                处理订单相关请求(如创建订单、查订单)

                                                二、关键规则:确保多个 route.js 不冲突

                                                1. 同一目录下只能有一个 route.js: 单个文件夹内不能存在多个 route.js(如 app/api/user/ 下只能有一个 route.js),否则 Next.js 会报错;但该文件内可导出多个 HTTP 方法函数(GET/POST/PUT 等),处理同一路径的不同请求类型。
                                                1. 支持嵌套路径创建多 route.js: 可通过嵌套文件夹实现更细粒度的接口拆分,例如:
                                                    • app/api/user/detail/route.js/api/user/detail(查用户详情)
                                                    • app/api/user/edit/route.js/api/user/edit(编辑用户信息)
                                                1. 独立处理逻辑: 每个 route.js 是独立的模块,可编写专属的业务逻辑,互不干扰;也可复用公共工具函数(如数据库连接、数据验证)。

                                                三、多 route.js 的优势

                                                1. 接口模块化:按业务模块(用户、文章、订单)拆分 route.js,代码结构清晰,便于维护;
                                                1. 职责单一:每个 route.js 专注处理一类业务的接口,符合“单一职责原则”;
                                                1. 独立调试:可单独测试某一个 route.js 对应的接口,无需影响其他接口;
                                                1. 灵活扩展:新增业务接口时,只需新增对应文件夹和 route.js,无需修改现有代码。

                                                四、示例:多 route.js 的实际配置

                                                app/api/user/route.js 示例代码:
                                                app/api/post/route.js 示例代码:

                                                五、注意事项

                                                1. 避免路径冗余:不要创建无意义的嵌套路径(如 api/user/user/route.js),保持路径简洁;
                                                1. 公共逻辑抽离:多个 route.js 若需复用相同逻辑(如鉴权、数据库连接),可抽离为公共函数/中间件,避免重复代码;
                                                1. 路由冲突:确保 route.js 的路径不与前端页面路由(如 app/user/page.js)冲突,Next.js 会优先匹配 route.js 对应的 API 路由。
                                                综上,多个 route.js 是 Next.js 15 构建多接口的标准方式,核心是通过“文件路径对应 API 路径”的规则,实现接口的模块化管理。

                                                022 Using Middleware - 中间件

                                                🗒️
                                                注意middleware文件约定已被弃用,并已重命名为proxy。有关更多详细信息,请参阅迁移至代理https://nextjs.org/docs/app/api-reference/file-conventions/proxy

                                                一、基础设置:文件位置与命名规则

                                                1. 文件路径:不依赖app文件夹,需放在项目根目录(与package.json同级)
                                                1. 文件名:固定为middleware.js(保留文件名,不可自定义)
                                                1. 核心导出:必须导出名为middleware的函数(函数名固定,Next.js自动识别)

                                                二、函数结构与依赖导入

                                                1. 函数参数与返回值
                                                    • 自动接收request请求对象(与路由处理程序一致)
                                                    • 必须返回NextResponse(需从next/server导入,不可省略)
                                                1. NextResponse 核心功能
                                                    • 基础能力:从零创建新响应、转发请求(通过next()方法,将请求导向原始目的地)
                                                    • 实用场景:实现重定向(如未认证用户跳转登录页)、修改请求头/参数等

                                                三、核心作用与运行机制

                                                1. 核心定位:非“请求处理者”,而是“请求拦截器”
                                                    • 主要用途:查看请求内容、修改请求参数、阻止非法请求、实现路由级认证
                                                    • 特殊能力:可拦截网站所有请求(包括页面请求、图片/图标等资源请求)
                                                1. 运行特性:每次请求触发(无论访问哪个页面/路由),重启开发服务器后生效

                                                四、请求过滤:matcher 配置

                                                1. 配置方式:导出config对象(变量/常量均可,需为对象类型),设置matcher属性
                                                1. 功能作用:指定哪些请求会触发中间件,过滤无关请求(如仅拦截特定页面请求,排除图片请求)
                                                1. 高级用法:支持数组格式与占位符,匹配多路由(如['/news/:id', '/profile']),具体规则参考Next.js官方文档

                                                五、实际验证与注意事项

                                                1. 服务器日志验证:重启开发服务器后加载页面,日志会显示中间件为每个请求运行(如访问新闻页时,日志包含页面请求、页面内图片请求)
                                                1. 课程定位:当前项目暂无需使用中间件,但属于Next.js路由体系核心功能,需掌握其原理以应对复杂场景(如全局认证、请求过滤)

                                                📎 参考文章

                                                • 一些引用
                                                • 引用文章
                                                 
                                                💡
                                                欢迎您在底部评论区留言,一起交流~
                                                上一篇
                                                第一节 大脑:重新认识你自己
                                                下一篇
                                                Harness Engineering - 搭建Mini Harness
                                                Loading...