Next.js 中不可忽视的路由系统
前言
路由是支撑项目的基石,路由的存在,让页面之间可以实现跳转,传参,甚至是页面的展示都离不开路由。
在 Next.js v13 版本中引入了新的路由模式 App Router,它支持共享布局、嵌套路由、错误处理等,相比于之前的 Pages Router,App Router 制定了更加完善的规范,使代码更好被组织和管理。
定义路由
Next.js 中使用的是基于文件系统的路由,也就是使用文件夹来定义路由,每次定义的文件夹名称就会映射到对应的 URL 中。
要想使 URL 可以访问,必须在其对应的文件夹中存在 page.js 文件,如下图所示,/dashboard/analytics 路由是不可访问的,因为在 analytics 文件夹下不存在 page.js 文件。
其中 page.js 文件是 Next.js 约定的,必须为这个名称,否则不识别,作用是为路由创建用户界面,即 UI。
链接与导航
使用 Link 组件
<Link> 组件是 Next.js 中的一个内置组件,是官方推荐的方式,可以直接在 next/link 中导入并使用。
import Link from 'next/link'
export default function Page() {
return <Link href="/dashboard">Dashboard</Link>
}
使用 useRouter 钩子
使用 useRouter 钩子可以让我们以编程式的方式实现导航,直接在 next/navigation 中引入。
值得注意的是,在使用 useRouter 的组件中需要在最顶部书写 use client 用来表示这是一个客户端组件。
'use client'
import { useRouter } from 'next/navigation'
export default function Page() {
const router = useRouter()
return (
<button type="button" onClick={() => router.push('/dashboard')}>
Dashboard
</button>
)
}
使用 redirect 功能
可以在服务端组件使用 redirect 来实现导航,
import { redirect } from 'next/navigation'
async function fetchTeam(id: string) {
const res = await fetch('https://...')
if (!res.ok) return undefined
return res.json()
}
export default async function Profile({ params }: { params: { id: string } }) {
const team = await fetchTeam(params.id)
if (!team) {
redirect('/login')
}
// ...
}
路由组
概念
在 Next.js 的 app 目录中,嵌套文件夹会映射到 URL 路径,Next.js 中有一个路由组的概念,这会帮助我们把文件夹标记为路由组,可以用来防止此文件夹包含在路由的 URL 路径中。
路由组的使用方式:通过将文件夹的名称括在括号中来创建路由组:(folderName)。
作用
组织路由而不影响 URL 路径
下图中的 (marketing) 和 (shop) 这两个文件夹,这表示创建了两个路由组,在 URL 中将会省略括号中的文件夹,映射到 URL 中的路径就是 /about 和 /blog。
从而可以使我们在不影响 URL 的情况下组织路由将相关路由保存在一起。
虽然 (marketing) 和 (shop) 这两个路由组中的路由共享相同的 URL 层次结构,我们仍然可以在其文件夹中创建 layout.js 文件,实现不同的路由组能够拥有不同的布局。
选择特定的路由到布局中
例如,我们可以创建一个新的路由组 (shop),可以将路由 account 和 cart 放置到能够共享相同布局的路由组 (shop) 中,而路由组之外的 checkout 路由将不会共享路由组中的布局。
创建多个根布局
创建多个根布局,我们可以直接在每个路由组中创建 layout.js 文件,值得注意的是,还需要删除顶层的 layout.js 文件,这有助于我们根据不同的业务需求渲染不同的 UI 组件。
因为顶层的 layout.js 文件被删除,因此还需要将 <html> 和 <body> 标签添加到每个根布局中。
值得注意的是,包含路由组的路由不应解析为与其他路由相同的 URL 路径。
动态路由
概念
我们可以通过将文件夹的名称括在方括号中创建动态段 [folderName],如 [id]、[slug] 等,动态段将会作为 params 属性传递给 layout、page 等函数中。
示例
例如,博客路由为 app/blog/[slug]/page.js,其中 [slug] 就可以表示为博客帖子的动态分段。
export default function Page({ params }) {
return <div>My Post: {params.slug}</div>
}
当我们访问 /blog/a 的时候,params 对应的值为 { slug: 'a' }。
当我们访问 /blog/b 的时候,params 对应的值为 { slug: 'b' }。
当我们访问 /blog/c 的时候,params 对应的值为 { slug: 'c' }。
还有一点需要注意,在括号 [...folderName] 内添加省略号,可以扩展动态段以捕获所有后续段。
例如,博客路由为 app/shop/[...slug]/page.js,相比于 [slug] 这种形式,[...slug] 可以匹配所有的参数。可以匹配 /shop/clothes、 /shop/clothes/tops、/shop/clothes/tops/t-shirts 等。
当我们访问 /shop/a 的时候,params 对应的值为 { slug: ['a'] }。
当我们访问 /shop/a/b 的时候,params 对应的值为 { slug: ['a', 'b'] }。
当我们访问 /shop/a/b/c 的时候,params 对应的值为 { slug: ['a', 'b', 'c'] }。
平行路由
平行路由允许我们有条件的渲染同一布局中的一个或者多个页面,例如,使用平行路由可以同时渲染下图中的两个页面,team 和 analytics 页面。
平行路由是使用命令插槽创建的,插槽是按照 @folder 约定定义的,例如,下图中的文件结构中定义了两个插槽 @analytics 和 @team。
插槽会作为属性传递给共享的父布局,例如上图的文件结构中,app/layout.js 布局组件会接受两个传入的插槽属性 @analytics 和 @team,与 children 属性并行渲染。
export default function Layout({ children, team, analytics }) {
return (
<>
{children}
{team}
{analytics}
</>
)
}
值得注意的是,平行路由和路由组一样,不会影响 URL。例如,/@analytics/views 文件夹所对应的真实的 URL 地址为 /views。
而实际上 children 是一个隐式的插槽,意味着 app/page.js 相当于 app/@children/page.js,因此不需要映射到文件夹。
总结
Next.js 中的路由系统,相比于直接使用 React 开发,从头配置路由便捷很多,同时 Next.js 也帮我们在内部封装了许多功能,就基于文件系统的路由本身来说,大大提高开发者的工作效率,文件即路由,免去那些繁杂的配置,像路由组、平行路由这些出现在 Next.js 中的新概念,更是让我们认识到 Next.js 的强大。
转载自:https://juejin.cn/post/7371641316114464804