Skip to content

深入路由与页面构建

本节课我们将一起实现“GitHub 统计”页面,并应用动态路由、布局、加载 UI 和错误处理等核心知识点。我们将以 github.com/yangjh-xbmu/Web-develop 仓库作为数据来源。

教学目标:

  1. 在导航栏添加“GitHub 统计”链接。
  2. 创建 /github-stats 页面,显示提交列表(例如提交信息和作者)。
  3. /github-stats 创建嵌套布局。
  4. 实现动态路由 /github-stats/commits/[commitId] 以显示单次提交的详细信息(如提交日期和变更的文件)。
  5. /github-stats 路由段添加加载状态 UI ( loading.js )。
  6. /github-stats 路由段添加错误处理 UI ( error.js )。

步骤 1: 修改导航栏并创建基础的 GitHub 统计页面

首先,我们需要在导航栏中添加一个指向新页面的链接。

  1. 修改导航栏组件 ( Navbar.js )

    Navbar.js 中添加一个新的链接:

    • 讲解点 :我们使用了 Next.js 的 <Link> 组件进行客户端导航,这比传统的 <a> 标签性能更好。
  2. 创建 GitHub 统计页面 ( page.js )

    src/app 目录下创建一个新的文件夹 github-stats ,然后在其中创建 page.js 文件。

    • 讲解点 :Next.js 的 App Router 使用基于文件夹的路由系统。 src/app/github-stats/page.js 文件会自动映射到 /github-stats 路径。

现在,运行 npm run dev ,应该能在导航栏看到“GitHub 统计”链接,点击后会显示这个基本页面。

步骤 2: 为 GitHub 统计创建嵌套布局 ( layout.js )

我们可以为 /github-stats 路径下的所有页面创建一个共享的布局。这个布局会嵌套在根布局 layout.js 内部。

  1. 创建嵌套布局文件

    在 src/app/github-stats 目录下创建 layout.js 文件:

    • 讲解点 :
      • layout.js 文件用于定义共享 UI。此布局将应用于 /github-stats 及其所有子路由。
      • 它会自动接收 children props,代表该布局包裹的页面或子布局。
      • 根布局 layout.js 中的 Navbar 和 Footer 依然会显示,因为这个布局是嵌套在根布局内的。

步骤 3: 获取并显示提交列表 (服务器组件数据获取)

现在我们来修改 src/app/github-stats/page.js ,使其从 GitHub API 获取提交数据并展示。

  • 讲解点 :
    • 服务器组件 (Server Components) : GitHubStatsPage 现在是一个 async 函数。这意味着它是一个服务器组件,可以在服务器上直接执行数据获取 ( getCommits )。
    • 数据获取 : 使用 fetch API 从 GitHub 获取数据。
    • 错误处理 (初步) : try…catch 块用于捕获 getCommits 中可能发生的错误。如果获取失败,我们会显示一个错误消息。更完善的错误处理将通过 error.js 实现。
    • 链接到动态路由 : <Link href={ /github-stats/commits/${commit.sha} }> 为每个提交创建了一个指向其详细页面的链接, commit.sha 将作为动态参数。
    • API 速率限制 : GitHub API 对未认证请求有速率限制。

步骤 4: 实现动态路由显示提交详情

现在我们创建动态路由页面,用于显示单个提交的详细信息。

  1. 创建动态路由文件夹和页面文件

    在 src/app/github-stats 目录下创建 commits 文件夹,然后在 commits 文件夹内创建 [commitId] 文件夹 (方括号表示动态段),最后在 [commitId] 文件夹内创建 page.js 。 完整路径: src/app/github-stats/commits/[commitId]/page.js

  2. 编写动态路由页面组件

  • 讲解点 :
    • 动态路由参数 : CommitDetailPage 组件通过 params prop 接收动态路由参数。 params.commitId 对应于 URL 中的 [commitId] 段。
    • 数据获取 : 同样使用 async/await 和 fetch 获取特定提交的详细信息。
    • generateMetadata : (可选) 展示了如何为动态页面生成元数据 (如页面标题),这对于 SEO 很有用。

步骤 5: 实现加载状态 UI ( loading.js )

当数据获取需要时间时,我们可以显示一个加载指示器。

  1. 创建 loading.js 文件

    在 src/app/github-stats 目录下创建 loading.js 文件:

    • 讲解点 :
      • loading.js 文件导出的组件会在其所在路由段(这里是 /github-stats 及其子路由)的内容加载完成前显示。
      • Next.js 会自动将 loading.js 包裹在 React Suspense 边界内。
      • 您可以为更细粒度的动态路由(如 src/app/github-stats/commits/[commitId]/loading.js )创建特定的加载 UI,如果该页面的数据加载也比较耗时。 为了明显看到加载效果,您可以在 getCommits 或 getCommitDetails 函数中人为增加延迟: await new Promise(resolve => setTimeout(resolve, 2000)); // 模拟2秒延迟

步骤 6: 实现错误处理 UI ( error.js )

如果数据获取失败或组件渲染时发生错误,我们可以显示一个友好的错误页面。

  1. 创建 error.js 文件

    在 src/app/github-stats 目录下创建 error.js 文件:

  • 讲解点 :

    • ‘use client’ : 错误组件必须是客户端组件。

    • Props : 错误组件接收两个 props:

      • error : 一个 JavaScript Error 对象。
      • reset : 一个函数,调用它可以尝试重新渲染产生错误的路由段。
    • 错误记录 : useEffect 可以用来将错误信息发送到日志服务。

    • 用户体验 : 提供一个“再试一次”的按钮,让用户有机会从临时性错误中恢复。 要测试 error.js ,您可以:

    • 在 getCommits 或 getCommitDetails 中故意 throw new Error(‘Simulated fetch error’);

    • 或者修改 API URL 为一个无效的地址。

总结与回顾

通过这个“GitHub 统计”功能的实现,我们学习并实践了:

  • 动态路由 ( [commitId]/page.js ) : 如何根据 URL 参数动态生成页面内容。
  • 布局组件 ( layout.js ) : 如何为特定路由段创建共享 UI 结构,并理解嵌套布局的概念。
  • 加载状态 UI ( loading.js ) : 如何使用 Suspense 和 loading.js 提升数据加载时的用户体验。
  • 错误处理 ( error.js ) : 如何创建错误边界,优雅地处理运行时错误并提供恢复机制。
  • 服务器组件数据获取 : 如何在服务器组件中直接使用 async/await 获取外部数据。