Nextjs 学习笔记
主要侧重于 13.x 之后给出的 break change ,修正写代码过程中可能遇到的版本问题
总结:
- Link 标签不用再写 a 标签,因为直接解析为 a 标签
- src/app 目录下所有页面默认是 服务器组件,需要定义 客户端组件 时在顶部添加 “use client”
- 3、自定义共享布局、样式:src/app/layout.tsx、src/app/global.css
- 4、自动按照路由进行代码分割
- 5、预渲染
- SSG 静态页面生成:getStaticPaths 被改为 generateStaticParams + revalidate - 在构建时生成 HTML +
export const revalidate
增量静态再生- 增量静态再生 (ISR):运行时 生成或更新 静态页面的能力,能更新动态内容而无需重新构建 - revalidate 配置页面的「重新验证时间」,到点儿后在运行时生成页面,实现静态页面的增量更新
- SSR 服务端渲染:getServerSideProps - 每次请求时在服务端运行得到「html并嵌入拉取到的动态数据」 -> 返回需要的 HTML + 所需的js代码
- SSG 静态页面生成:getStaticPaths 被改为 generateStaticParams + revalidate - 在构建时生成 HTML +
- 6、API Router
一、导航相关 <Link>
- app 目录中,页面默认是服务器组件;pages 目录中,页面是客户端组件
- app 目录中,定义客户端组件需要在文件顶部添加 ‘use client’ 指令
1、客户端导航:Nextjs 的前端部分提供内置的「文件系统路由」+ Link
- Nextjs 13.x 版本开始,
<Link>
组件在使用时不用再写<a>
标签,因为在渲染时会把 Link 标签解析为 a 标签- 实现了「客户端导航」的方式,浏览器不会重新加载整个页面(a标签会触发重新刷新整个页面
- Nextjs 13.x 版本开始,「文件系统路由」从
pages/index.js
[旧方式]逐渐改为src/app/page.tsx
[新app模式]- 旧方式缺点:旧方式容易上手,按文件路径即可推论路由,但复杂嵌套需要写赘余代码
- 新方式优点:支持 自定义共享布局,在
src/app/layout.tsx
可自定义共享的布局(导航栏等)
2、代码分割:Nextjs 会自动进行
3、页面预加载 prefetching
:只要有 Link 标签出现在视口,Nextjs 会自动预取 Link 关联的页面代码 -> 点击跳转时后台已经加载好页面了 -> 秒切
二、静态资源加载
包括 css、image、public 文件
1、内置 css 、 sass、css-in-js
2、支持 css Module:
-
解决的核心问题: nextjs 中 css 全局命名空间问题,将类名进行局部化处理,使得每个组件的样式只在组件内部生效 + 方便 code splitting 代码分割
-
使用方式:很简单,把
style.css
改写/标记为style.module.css
即可,其中的类名会被转换为独一无二的标识符
3、全局变量
- 旧方法:在
pages/_app.js
中 import 引入全局 css 文件,利用_app.js
是整个应用的顶层组件特性,_app.js
包裹了所有页面的组件,引入的样式自然就应用到了全局 - 新方法:
src/app/global.css
三、预渲染
13.x 以上
- 新的数据获取方式:getStaticProps、getStaticPaths、getServerSideProps 已被 generateStaticParams 替代 - 只会在构建时预渲染来自
generateStaticParams
的参数- 增量静态再生 (ISR)
export const revalidate = 60 // Next.js 将在请求进来时使缓存失效,最多每 60 秒一次
// 如果收到一个尚未生成的路径的请求,Next.js 将按需服务器渲染该页面
export const dynamicParams = true // 或 false,对未知路径返回 404
export async function generateStaticParams() {
const posts = await fetch('https://xxx/blog').then((res) => res.json())
return posts.map((post) => ({
id: String(post.id),
}))
}
export default async function Page({ params }) {
const post = await fetch(`https://xxx/blog/${params.id}`).then((res) => res.json())
return (
<main>
<h1>{post.title}</h1>
<p>{post.content}</p>
</main>
)
}
// 这段代码的 增量静态再生 (ISR) 工作原理
- 在 `next build` 期间,生成所有已知的博客文章 (本示例中有 25 篇)
- 对这些页面的所有请求 (例如 `/blog/1`) 都被缓存并立即响应
- 60 秒过后,下一个请求仍然会显示缓存的 (陈旧的) 页面
- 缓存失效,并在后台开始生成页面的新版本
- 一旦成功生成,Next.js 将显示并缓存更新后的页面
- 如果请求 `/blog/26`,Next.js 将按需生成并缓存这个页面
- 增强 fetch:在 src/app 下的组件可以直接对数据获取,并且可以通过
next.revalidate
选项来实现增量静态再生(ISR),方便控制数据的更新频率
13.x 以下
默认情况下,Nextjs 会预渲染每个 page(也就是 预先为每个 page 生成 HTML 文件,而不是由 客户端 js 来生成 - 所以下面说的方法都是在「服务端」执行的,都不会被打包进 js bundle 里面
- 形式1:静态生成 - 生成 HTML 时机是「构建时」,并在每次页面请求时「重复使用」
- 在生产环境中,运行
next build
为该页面生成一次 HTML,之后被 CDN 缓存(托管 - 快) - 在开发环境/本地环境中,getStaticProps runs on every request
- 在生产环境中,运行
- 形式2:服务端渲染 - 生成时机是「每次页面请求时重新生成 HTML」
1、静态生成(static generation):别名SSG
这种静态生成的页面,分为「不带数据」(默认)的静态页面和「带数据」的静态页面。
需要获取外部数据的静态生成:
- 页面内容 取决于数据 – getStaticProps
- 该函数在「构建时」被调用,在预渲染时,将 props 作为参数传入页面
- [动态路由]paths 路径取决于数据 – getStaticPaths
- 例如使用
src/app/[id].tsx
来动态访问文件 - 该函数在「构建时」被调用,指定要被与渲染的数据
- 例如使用
nextjs 中 补丁 fetch 在客户端和服务端都可以执行,不需要再 import
// getStaticPaths、getStaticProps - 在同一文件,通过 export 导出 async 的异步函数
function Blog({posts}) {
// part① A React Component to render this page
return <ul>{posts.map((it) => (<li>{it.title}</li>))}</ul>
}
export async function getStaticPaths() {
// part② getStaticPaths which returnsn an array of possible values for ids
const res = await fetch('http://xxxx/posts'); // 外部查询
const post = await res.json();
const paths = posts.map(it => ({ params: { id: it.id } })); // 传递 params 数据,params 中的属性名和文档的 [id].tsx 的 key 相同
return { paths , fallback: false } // 其他非 paths 的路由为 404
}
export async funciton getStaticProps({ params }){ // 入参来源于 getStaticPaths
// part③ getStaticProps which fetches necessary data for the post with id
const res = await fetch(`http://xxxx/posts/${params.id}`);
const post = await res.json(); // 外部查询
return { props: { posts } } // 向页面传递博文数据
}
export default Blog
2、服务端渲染(server-side rendering):别名SSR/动态渲染
服务端在页面被请求时,执行当前页面内导出的异步函数 getServerSideProps 后再进行预渲染
- 写法类似于 getStaticProps,只是执行时机不同 - 构建时和请求时
四、客户端渲染
如果不需要预渲染,则可以采用客户端渲染 - 可以组合采用「静态生成(预渲染)不需要数据的部分 + 请求时,在客户端 js 请求拿到数据后再渲染」
五、API Routes - 在 Nextjs 中创建后端 API 的方式
13.x 以上的版本 pages/api/* API 路由已被 route.js (路由处理程序) 特殊文件替代
原理:Nextjs 的路由系统 API Routes,文件名就是路由路径的一部分
- 客户端向服务端发起这个路径的请求时,Nextjs 就自动调取这个文件来处理请求
语法:文件中导出一个默认函数,接收两个参数
- req - 请求对象,包含方法、头部信息、查询参数、请求体等
- res - 响应对象,可以设置请求状态码、头部信息、响应体等
迭代:采用 src/app
的路由方式后,API Routes 的文件也从 pages/api
转移到 src/app/api
- 常见:
src/app/api/user/route.js
定义api/user/
相关路由
export default function handler(req, res) {
res.status(200).json({ msg: 'hello, nextjs' })
}
- 注意事项:不要在 getStaticProps 和 getStaticPaths 中调用 API Route:以为这两个函数都是在预渲染 - 服务端直接执行的,所以可以直接写服务端代码,例如请求数据库等