-
Notifications
You must be signed in to change notification settings - Fork 1
Description
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.js
、loading.js
、not-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.js
、layout.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 使用。