Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Open
qufei1993 opened this issue Sep 16, 2023 · 0 comments
Open
Assignees
Labels

Comments

@qufei1993
Copy link
Owner

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 使用。

@qufei1993 qufei1993 self-assigned this Sep 16, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

1 participant