【Next.js 进阶】App Router的高级用法(下)

前言

先附上源码地址:next-ts-seed

之前介绍了Next.js App Router的基本使用:一文梳理Next.js 14的App Router,和包含平行路由的一些高级用法:【Next.js 进阶】App Router的高级用法(上),本篇继续讲解App Router的一些高级用法

对Next.js14项目搭建还不熟悉的,可参考我的另一篇文章:给上市公司从0到1搭建Next.js14项目

1. 拦截路由

拦截路由允许你在当前布局内加载应用其他部分的路由,通常与平行路由一同使用,以实现Modal对话框效果

例如图片中左边的路由为"/feed",当点击图片进行路由跳转到"/photo/123"时,浏览器上的路径被更改为"/photo/123",但/photo/123的内容以对话框Modal的形式展示在路由"/feed"上

而当在浏览器中直接输入路由"/photo/123"或刷新浏览器时,页面将直接呈现/photo/123的内容,而非以对话框Modal的形式呈现

在 Next.js 中,实现拦截路由需要你在命名文件夹的时候以 (..) 开头,规则为:

文件命名 匹配层级
(.) 表示匹配同一层级
(..) 表示匹配上一层级
(..)(..) 表示匹配上上层级
(...) 表示匹配根目录

但是要注意的是,这个匹配的是路由的层级而不是文件夹的层级,就比如路由组、平行路由这些不会影响 URL 的文件夹就不会被计算层级。

1. 新建app/food/photo/page.tsx

该页面为输入路由"/food/photo"或刷新浏览器时,页面呈现的内容

js 复制代码
export default function Page() {
  return <article>路由photo</article>;
}

2. 新建app/food/@modal/(.)photo/page.tsx

平行路由@modal不算url的层级,因此文件夹photo与文件夹(.)photo都在文件夹food下,属于同一层级,因此括号中使用一个点

js 复制代码
export default function Page() {
  return <div style={{ width: 500, height: 500, position: 'absolute', background: 'blue' }}>拦截路由photo</div>;
}

3. 新建app/food/layout.tsx

在layout中定义平行路由的插槽modal

js 复制代码
export default function Layout({ children, modal }: { children: React.ReactNode; modal: React.ReactNode }) {
  return (
    <section>
      {children}
      {modal}
    </section>
  );
}

4. 新建app/food/page.tsx

定义一个跳转到/photo的链接

js 复制代码
import Link from 'next/link';

export default function Page() {
  return (
    <article>
      <Link href="/food/photo">图片</Link>
    </article>
  );
}

5. 新建app/food/default.tsx

定义平行路由children插槽的默认文件

js 复制代码
export default function Default() {
  return null;
}

6. 新建app/food/@modal/default.tsx

定义平行路由modal插槽的默认文件

js 复制代码
export default function Default() {
  return null;
}

重启项目,访问路由/food,点击图片跳转到/food/photo,但页面显示的内容是@modal/(.)photo中的内容

刷新浏览器,此时路由为/food/photo,页面直接显示为"路由photo"

2. API 路由

API 路由在Next.js 14中又被称为Route Handlers(路由拦截器)。作为node中间层,可用来封装业务逻辑,减少客户端bundle体积;也可作为网关代理,隐藏真实后端接口

1. 基本使用

与page.tsx文件会自动映射为页面的路由一样,app目录下的route.ts文件会映射为一个api接口

为了避免route.ts与page.tsx冲突,可在app下新建api文件夹,专门用于存放API路由

1. 新建app/api/route.ts

js 复制代码
export async function GET() {
  return Response.json({ name: '张三' });
}

启动项目,例如我的端口号为3001,在浏览器中访问http://localhost:3001/api可以看到接口返回{ name: '张三' }

2. 修改app/page.tsx

在路由页面中使用API 路由

js 复制代码
async function getData() {
  const data = await fetch('http://localhost:3001/api');
  return data.json();
}

export default async function Home() {
  const data = await getData();
  return <article>{data.name}</article>;
}

访问http://localhost:3001,页面显示为张三

在项目中,可封装后台的业务逻辑

js 复制代码
export async function GET() {
  const res = await fetch('https://www.test.com/...');
  const data = await res.json();
  //处理数据...
  return Response.json({ data });
}

2. 动态API路由

动态API路由文件命名规则与路由文件一致

1. folderName

获取单个参数

新建app/api/id/route.ts

js 复制代码
export async function GET(request: Request, { params }: { params: { id: string } }) {
  return Response.json({ name: '张三', id: params.id });
}

访问http://localhost:3001/api/1,页面返回{"name":"张三","id":"1"}

2. ...folderName

获取多个参数(至少得有一个参数)

新建app/api/...key/route.ts

js 复制代码
export async function GET(request: Request, { params }: { params: { key: string[] } }) {
  const key = params.key;
  return Response.json({ key });
}

访问http://localhost:3001/api/1/2,页面返回{"key":"1","2"}

3. \[...folderName]

获取多个参数(可一个参数都没有)

新建app/blog/\[...key]/route.ts

js 复制代码
export async function GET(request: Request, { params }: { params: { key: string[] } }) {
  const key = params.key;
  return Response.json({ key });
}

访问http://localhost:3001/api/blog,页面返回一个空对象{}

3. 重定向

1. 客户端组件重定向

使用useRouter进行重定向

点击按钮,使用router.push进行路由跳转

js 复制代码
'use client';

import { useRouter } from 'next/navigation';

export default function Page() {
  const router = useRouter();

  return (
    <button type="button" onClick={() => router.push('/login')}>
      Dashboard
    </button>
  );
}

2. 服务端组件重定向

当接口请求失败时,使用redirect方法进行重定向

js 复制代码
import { redirect } from 'next/navigation';

async function fetchTeam(id) {
  const res = await fetch('https://...');
  if (!res.ok) return undefined;
  return res.json();
}

export default async function Profile({ params }) {
  const team = await fetchTeam(params.id);
  if (!team) {
    redirect('/login');
  }

  // ...
}

3. 中间件重定向

当cookie中没有验证信息时,使用NextResponse.redirect进行重定向

js 复制代码
import { NextResponse } from 'next/server';

import type { NextRequest } from 'next/server';

export function middleware(request: NextRequest) {
  const token = request.cookies.get('token');
  if (token) {
    return NextResponse.next();
  } else {
    return NextResponse.redirect(new URL('/login', request.url));
  }
}

export const config = {
  matcher: '/blog/:path*',
};

结尾

对Next.js感兴趣的,可先关注我,后续将继续更新相关内容

参考资料:

nextjs.org/docs/app/bu...

相关推荐
To_OC2 小时前
别再串行写 await 了,Promise.all 才是并行请求的正确打开方式
前端·javascript·promise
To_OC2 小时前
LC 17 电话号码的字母组合:我的回溯算法,就是从这道题开窍的
javascript·算法·leetcode
vipbic2 小时前
中后台越做越乱后,我用插件化把它救回来了
前端·vue.js
Hyyy3 小时前
Computer Use 适合做什么,不适合做什么——一次真实使用后的思考
前端
小和尚同志3 小时前
前端 AI 单元测试思考与落地
前端·人工智能·aigc
invicinble4 小时前
c端系统,其实更像一个信息展示平台
前端
你怎么知道我是队长5 小时前
JavaScript的变量和数据类型介绍
开发语言·javascript·ecmascript
李姆斯5 小时前
管理是否可以被完全量化
前端·产品经理·团队管理
名字还没想好☜6 小时前
Next.js 中间件实战:鉴权、重定向与 A/B 分流
开发语言·前端·javascript·中间件·react·next.js
广州灵眸科技有限公司6 小时前
瑞芯微RV1126B开发板(EASY-EAI-PI2) INI文件操作
java·前端·javascript·网络·人工智能