Skip to content

Next.js 13 App Router 的这几个关键知识点你应该掌握! #54

@qufei1993

Description

@qufei1993

Next.js 13 一个重大的变化是带来了新的路由系统 “App Router”,这是一种基于文件系统的新路由模式,构建在 React Server Component 之上。较之前的 react-router-dom 这种路由编写方式完全不同。也是当前编写 Next.js 应用程序的默认方式。

使用命令 npx create-next-app@latest nextjs-app-routes 创建一个项目。

文件结构

以下是一个 App Router 的文件结构,文件名称反映了组件的类型,例如 page.js 是页面组件、layout.js 是一个布局组件。除此之外还有一些其它文件名约定,例如:error.jsloading.jsnot-found.js 等等。

src
└── app
    ├── home
    │   ├── layout.js
    │   └── page.js
    └── login
        ├── layout.js
        └── page.js

文件的目录结构最终会反映到请求的页面路径上,以下目录结构对应两个页面路径:

  • http://localhost:3000/home
  • http://localhost:3000/login

路由组

home 组件代表首页,你可能只是为了按照页面或功能进行的目录分组,不想每次请求页面时都带上 /home

接下来就要用上 “路由组” 功能了,将目录放在括号里,Next.js 在幕后会帮助我们消除 home 这个路径段。之后可以通过 http://localhost:3000/ 访问 home 页面组件。

src
└── app
    ├── (home)
    │   ├── layout.js
    │   └── page.js

动态路由

动态路由是页面路由中会包含一些动态的值,要创建动态路由,需将文件名放在 [] 方括号中。

如下所示,创建一个 shop/[slug] 路由,这种方式 slug 值只能是一个,如果路径想表示多个值使用 shop/[...slug]

src
└── app
    ├── (home)
    │   ├── layout.js
    │   ├── page.js
    │   └── shop
    │       └── [slug] # [...slug] 表示路径可以是多个值
    │           └── page.js
路由               请求 URL                          路径参数
shop/[slug]       http://localhost:3000/shop/1      { slug: '1' }
shop/[...slug]    http://localhost:3000/shop/1/2    { slug: [ '1', '2' ] }

Layout

Layout 组件是 App Router 的一个重大特性。Layout 是页面组件的基础组件,可以简单理解为,Layout 组件包含了 Page 组件,可以在多个页面共享同一个布局

在 Layout 组件内,我们可以处理一些通用的 UI 样式、公共数据处理

如下代码所示:

// src/(home)/app/layout.js
export default async function HomeLayout({ children }) {
  const user = await getUser();

  return (
    <div>
      <header> 用户:{user.username} </header>
      <section> {children} </section>
    </div>
  )
}
// 模拟从服务器获取数据
const getUser = async () => Promise.resolve({ username: 'admin' });

App Router 模式下默认的组件类型是 Server Component,通过名字也能猜到,它运行在服务端(默认 Node.js 运行时),可以搭配 Node.js 生态系统使用。Server Component 不是本节的重点,后续章节重点介绍。

Server Component 组件可以是异步组件,搭配 async/await 直接获取数据方便很多。注意 Client Component 组件不能是异步的。

这里还可以使用 React 中的 use Hook 以看似同步的方式获取数据。最终效果同上面使用 async/await 一样。

import { use } from 'react';
export default function HomeLayout({ children }) {
  const config = use(getUser());
  ...
}

内置 SEO 支持

page.jslayout.js 组件中,通过导出的 metadata 常量设置页面的元数据。

注意,如果同时设置,page.js 组件的优先级大于 layout.js

// src/(home)/app/layout.js
export const metadata = {
  title: 'Home',
  description: 'Home...',
}

如果需要访问动态数据,使用 generateMetadata() 函数

export async function generateMetadata(
  { params, searchParams }
) {
  const shop = await fetch(`https://.../${searchParams.id}`).then((res) => res.json())
  return { title: shop.name };
}

API 路由

定义 API 路由的文件约定是 route.js。

以下文件结构对应的 API 路由为 http://localhost:3000/api/user

注意 API 路由也必须写在 app 目录下,否则是不生效的。

src
└── app
    ├── api
    │   └── user
    │       └── route.js

导出想要支持的 HTTP Method。

import { NextResponse } from 'next/server';
 
export async function GET() {
  return NextResponse.json({ username: 'admin' });
}
 
export async function POST(request) {
  const body = await request.json();
  const data = await getData(body);
 
  return NextResponse.json(data);
}

总结

以上是 Next.js App Router 的一些关键知识点,也是项目中使用最多的,完整的推荐阅读官方的文档 https://nextjs.org/docs/app/building-your-application/routing。

如果想了解 Next.js 最新动态和相关知识,请关注编程界 Next.js 专栏。下一期我们聊聊 Next.js 的 Server Component 使用。

Metadata

Metadata

Assignees

Labels

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions