一、NextJs14快速上手
从Nextjs13开始,更推荐使用App Router,我们也基于App Router来展开。
我们通过 npx create-next-app@latest 创建项目并使用其默认选项。
在Nextjs13+中,默认都是服务端组件,如果我们要使用 hook 等,则需要通过 'use client' 声明为 客户端组件
路由
Nextjs 使用基于文件系统的路由,一个 page.js/ts/jsx/tsx 会作为路由的 UI 进行渲染。
Pages 和 Layouts 和 Templates
一个 page.js/ts/jsx/tsx 文件是一个路由的 UI 界面,这个文件总是这个路由子树的叶子节点
一个 layout.tsx 中的内容会在多个子路由页面内共享,可以嵌套,在导航时会保留布局状态和交互,不会重新渲染
最顶层要有一个
Root Layout,其必须包含html和body标签,一般来说会使用app/layout.tsx作为Root Layout但不是必须的
layout会包裹page的内容放到children属性的渲染位置
比如我们创建目录结构如下:
1 | - app |
我们代码如下:
1 | // /app/dashboard/layout.tsx |
1 | // /app/dashboard/page.tsx |
当我们访问 /dashboard 路由时可以看到如下页面:
此时我们来完善一下/dashboard/setting的路由内容
1 | // /app/dashboard/settings/layout.tsx |
1 | // /app/dashboard/setting/page.tsx |
当我们访问 /dashboard/settings 路由时可以看到如下页面:
可见其路由渲染规则,
layout可以嵌套且会被下级路由共享,page作为路由的子节点来渲染页面
template 和 layout 比较相似,也一样会包裹每个子布局与页面,但是在共享 template 的路由之间导航时,不回保留状态,因此在一些依赖于 useState/useEffect 等副作用函数的情况下会更合适。
这里我们在之前的案例基础上,在dashboard目录下新建一个 template.tsx:
1 | // /app/dashboard/template.tsx |
此时再次刷新页面查看 /dashboard/settings 路由对应的页面:
我们可以得出结论,在嵌套情况下, **
template会在layout和child layout之间进行呈现 **
Link 和 Navigating
我们实现路由跳转有两种方式:
<Link></Link>组件跳转useRouter编程式导航
Link 是扩展的内置标签 a 标签,通过 href 属性指定跳转地址:
1 | import Link from 'next/link' |
useRouter 编程式路由导航,由于用到了 hook, 所以只能用于客户端组件。
1 | 'use client' |
如果是通过用户点击来触发路由导航,我们总是建议使用
Link组件来实现
路由组
在 app 目录下的文件夹名字会被映射为路由的 url,如果我们只想将文件夹用于组织文件而不影响路径,那么就可以使用路由组来实现,语法为 (foldername)
1 | - app |
路由组的命名除了组织代码之外没有特殊意义
使用路由组还要注意避免路径重复
动态路由
如果不确定具体的路由路径,可以创建动态路由,语法为 [foldername]
动态路由会作为 params 参数传递
1 | // /app/blog/[slug]/page.tsx |
还可以使用
[...foldername]来捕获后续路由参数,得到的params中的参数会是一个数组
平行路由
平行路由允许你同时或者有条件的渲染一个或多个页面在同一个layout中。
目录名使用@foldername创建。会作为参数传递给同级的layout。
假设有目录结构为:
1 | - app |
此时同级的layout即app/layout.tsx会接收这两个slots属性:
1 | // app/layout.tsx |
children属性是一个隐式的插槽,不需要映射到文件夹。这意味着app/page.tsx相当于app/@children/page.tsx
路由处理程序
路由处理程序仅在 App Router 下可用,类似于 Page Router 的 API Routes
路由处理程序定义在一个特殊的文件 route.ts 中,但是同级不能存在一个 page.js/ts/jsx/tsx 文件了。这样如果目录下是 page 文件就是页面, 是 route 文件就是 API 且遵循 Rest API 风格.
路由处理程序在GET请求时默认会进行缓存。请求方法支持GET, POST, PUT, DELETE, HEAD, PATCH, OPTIONS,如果要建立怎么方法的请求,将其作为函数名即可。
比如我们有文件 app/api/v1/blogs/route.ts 文件:
1 | // GET请求 /api/v1/blogs |
路由处理程序不进行缓存的几种方式:
- 将
Request对象与GET方法一起使用 - 使用非
GET请求的其他HTTP方法。 - 使用动态函数
- 手动指定动态模式
route handler可以根据目录结构来构建RESTful规范的接口,规范的请求方法为:
| 方法 | 场景 | 示例 |
|---|---|---|
GET |
获取数据 | 获取单个: GET /api/tasks/1 获取多个: GET /api/tasks?page=1&size=10 |
POST |
创建数据 | 创建单个: POST /api/tasks |
PATCH |
差量修改数据 | 修改单个: PATCH /api/tasks/1 |
PUT |
全量修改数据 | 修改单个: PUT /api/tasks/1 |
DELETE |
删除数据 | 删除单个: DELETE /api/tasks/1 删除多个: DELETE /api/tasks?ids=1,2,3 |
接口路径使用资源名词而非动词,动作应该由
HTTP Method来体现。接口路径中的资源名词使用复数。
完成以上功能,需要有文件目录如下:
1 | 目录结构如下 |
中间件
中间件也是一个特殊的文件,我们将其命名为 middleware.ts,但是要注意需要定义在项目根目录
示例:
1 | import type { NextRequest } from 'next/server' |
其他特殊文件
前边我们已经说了 layout, page, template, route, middleware 这几个作为文件名的特殊意义,还有一些其他文件也会被路由匹配并有其意义。
loading.tsx- 基于React.Suspense创建加载UI, 渲染完成后自动替换
可以将其效果理解为:
1 | <Layout> |
error.tsx- 处理错误
还有比较特殊的目录名,
_foldername以下划线开头的目录作为私有目录,不会被解析为路由,比如我们可以使用_components来存放一些用于当前同级页面的组件
数据获取
有四种方式使用获取数据:
- 在服务端组件使用
fetch - 在服务端组件使用第三方库
- 在客户端组件使用
Route Handlers - 在客户端组件使用第三方库
第三方库的内容不展开了,后边我们还会说到 React Query, 这里说一下两外两个方式
在服务端组件使用 fetch
Nextjs 扩展了原生的 fetch, 允许为每个请求配置缓存和重新验证行为
fetch的基本使用:
1 | async function getData() { |
默认情况下会自动缓存 fetch 请求的数据,即便是 POST 请求也会自动的缓存,除非是在 Route Hanler 中使用 POST 请求
重新验证数据有两种方式:
- 基于时间的重新验证,在经过一段时间后自动重新验证数据,对于不经常更改且新鲜度不高的数据很适用。
1 | fetch('http:', { next: { revalidate: 3600 } } ) |
- 按需重新验证,根据事件手动重新验证数据。
1 | fetch('', { next: { tags: ['collection'] } }) |
重新验证:
1 | 'use server' |
fetch在以下几种情况下不会缓存:
cache: 'no-store'添加到请求配置中revalidate: 0添加到请求配置中fetch请求位于POST方法的Route Handler中fetch请求使用动态数据headers/cookies之后发出的- 使用
const dynamic = 'force-dynamic'路由段 fetchCache路由段配置为跳过缓存fetch请求使用请求头Authorization / Cookie,并且组件树上有一个未缓存的请求
在客户端组件使用 Route Handlers
比如有目录如下:
1 | app |
我们可以这样来处理请求:
1 | // app/demo/page.tsx |
1 | // app/api/tasks/route.ts |
数据库操作会在后边说到
Prisma的时候再引入,这里用mock数据来模拟一下
Server Action是一个较新的特性,但是并不能很好的覆盖所有应用场景,所以个人不太推荐使用,这里也不展开说了。
基于以上内容,其实已经可以 Nextjs 的开发了,更全面的内容包括渲染、缓存、优化、配置等内容还是要参考官方文档来看,内容太丰富了,没有条件在这里继续展开了。
一、NextJs14快速上手