type
status
date
slug
summary
tags
category
icon
password

1. 前言

Next.js 14 提供了新的 App Router 作为默认的路由方案,文件夹的嵌套结构决定了路由的渲染或请求的返回处理。太棒了这逻辑清晰,再也不必手动配置 router 了,开发一路畅通了,家人们。
这简直就是危言耸听!那文档翻起来无异于海底捞针。
notion image
本文分为上下两篇,上篇主要以路由为核心,下篇补充网络请求以及各杂项。

2. 路由页面

例如有以下路由页面:
访问路径
页面组件
名称
/
app/page.js
主页
/blogs
app/blogs
文章列表
/blogs/1
app/blogs/[id]/page.js
文章详情(使用id)
/blogs/hello-next
app/blogs/[slug]/page.js
文章详情(使用slug)
/login
app/(auth)/login/page.js
登录
/forget-password
app/(auth)/forget-password
忘记密码
登录和忘记密码使用(auth)进行逻辑分组,不影响路径访问。
在路由渲染方面,还提供了诸如 layout.js、loading.js、error.js、not-found.js 以配置布局页面、加载页面、错误反馈页面、404页面。

3. 路由处理器

除了页面渲染,还有路由处理器(Route Handler)。笔者在使用这部分特性时摔过不少跟头,它不如 Pages Router 的 API Routes 那么直观。
假设有以下 API 接口:
  • GET api/v1/blogs
  • GET api/v1/blogs/1
  • POST api/v1/login { email, password }
  • GET api/v1/blogs?q=xxx
  • GET api/v1/blogs?q=xxx&&start=1&&end=2
在 route.js 中定义路由处理器:
每一个方法都有 request 参数,从中可以解析出所需的内容。请求对象的类型可以是 Request 或者 NextRequest,后者是扩展了前者功能的类型。在实际开发中,笔者使用的是后者。同理,响应对象的类型有 ResponseNextResponse

3.1 body

body 数据藏在 request.json() 中。

3.2 query && pathname

查询字符串藏在 request.nextUrl.searchParams 中。
  1. 如果是单个查询字符串:
  1. 如果是多个查询字符串:
pathname 藏在 request.nextUrl.pathname 下:

3.3 params

如果想要获取路由的动态参数 [id] 或 [slug],咋办?
这些数据就藏在路由处理器中的第二个参数中:

3.4 cookies

cookie 在用户登录时在响应豹纹中返回给前端,这在《图解HTTP》书中有形象的描述:
notion image
对应的豹纹如下:
notion image
可以看到,响应豹纹中通过 Set-Cookie 设置了 sid,以后客户端请求中自动携带了 Cookie,里面就放着 sid 数据。同理,cookie 里可以放 token。
有的接口需要把 token 信息传给服务器,因此获取 cookie 就变得尤为重要。在请求头和响应头中都可以获取到 Cookie,这里以请求头为例,利用 request.cookies.get('token')
如上,拿到 token 的值设置到请求头参数 Authorization 中。
next/headers 可以得到 cookie 方法, 删除的方式如下:

3.5 headers

在 3.1 中可以看到,在返回 json 数据时可以设置 headers。
如果想要获取 headers 信息(只读),从 next/headers 可以得到 headers 方法:

3.6 重定向

4. 在服务端组件中获取 URL 参数

在路由处理器中,可以从 request 中拿到很多东西,而到了服务端组件是没有 request 对象的。
在 page.js 中呈现的是某一路由的组件,从 props 中可以解构出 params 和 searchParams:

5. 在客户端组件中获取 URL 参数

以上是在服务端组件中获取参数的方式,而在客户端组件中利用客户端 hook 获取。

5.1 useRouter()

控制路由跳转、重定向等。
  • router.push(href: string, { scroll: boolean }) :对提供的路由执行客户端导航。在浏览器的历史堆栈中添加一个新条目。(可以用<Link> 组件代替。)
  • router.replace(href: string, { scroll: boolean }): 执行指向所提供路由的客户端导航,但不在浏览器历史堆栈中添加新条目。
  • router.refresh():刷新当前路由。向服务器发出新请求、重新获取数据请求并重新渲染服务器组件。客户端将合并更新的 React 服务器组件有效载荷,而不会丢失未受影响的客户端 React(如useState)或浏览器状态(如滚动位置)。
  • router.prefetch(href: string): 预取所提供的路由,以加快客户端转换。
  • router.back():返回浏览器历史堆栈中的前一个路由。
  • router.forward():向前导航至浏览器历史堆栈中的下一页。

5.2 usePathname()

获取 URL 上的 pathname,跟路径后面那一串,不包含查询字符串。

5.3 useSearchParams()

获取 URL 上的查询字符串。

5.4 useParams()

获取 URL 上的路由参数。

5.5 redirect()

在客户端组件中,无法直接使用 redirect(path, type) 方法,它的使用范围是:Server ComponentsRoute Handlers 以及 Server Actions
使用 useRouter() 相关方法代替或者这个🌰:https://nextjs.org/docs/app/api-reference/functions/redirect#client-component

6. 服务端组件和客户端组件的组合模式

服务端组件和客户端组件可以嵌套组合使用,但有所限制,它们各自的使用时机也不同。

6.1 服务端组件和客户端组件的使用时机

如果你想…
服务端组件
客户端组件
请求数据
直接获取后端资源
保持服务器中的敏感数据(获取 token、API key等等)
在服务器上保留大量依赖关系/减少客户端 JavaScript
添加交互性和事件监听器(onClick()、onChange()等)
使用状态和生命周期副作用(useState()、useReducer()、useEffect()等)
使用浏览器专用 API
使用依赖于状态、副作用或浏览器专用 API 的自定义钩子
使用 React Class 组件

6.2 不支持的模式:服务端组件作为模块引入客户端组件

下面代码中,将服务端组件作为模块嵌入客户端组件是不可行的:

6.3 支持的模式:服务端组件放入客户端插槽

作为 props,比如从插槽中将服务端组件插入客户端则是正确的:
 
Next.js 14 App Router 海底捞针我帮你做了!(下)了解了这些你就掌握了 React(下)
Eric 见嘉
Eric 见嘉
Less is more.
公告
type
status
date
slug
summary
tags
category
icon
password
💭
合抱之木,生于毫末;九层之台,起于累土;千里之行,始于足下。

关于我
土木转行的前端开发工程师,陆续分享技术干货。
联系我
微信公众号:见嘉 Being Dev