NextJs
B站Up:全栈码叔
什么是NextJS
NextJs基于React,
reactjs框架的功能比较单一,
主要是将html和javascript两者结合使用,
NextJs在此之外引入额外的框架功能:
- CLI/运行时/文件结构
- 路由
- 静态生成器static generation
- ISR
- SSR
- API
- Style
- Vercel静态托管平台
还有另外2个和NextJs比较相似的框架:
- GatsbyJs:生成静态页面,数据从本机抓取数据整合,通过GraphQL查询服务提供数据
- NestJS:更加偏向后端,继承了Controller、Service等层级,偏向MVC结构
NextJs框架目录
创建项目:
1 | npx create-next-app@latest |
- dev 开发模式启动
- build 构建生产环境应用
- start 启动生产环境服务器
- export 构建静态网站站点
原本的next export命令用于构建静态网站站点,
现在需要直接在next.config.mjs中配置output:
1 | const nextConfig = { |
这样,在运行npm run build的时候,就会自动生成out目录,下面存放的就是静态资源
.next文件是next项目生产环境下运行的文件,
在dev模式下也生成.next文件
静态路由
在文件根目录下创建pages文件,
在pages文件下创建的子文件可以通过路由进行导航:
- pages
- about
- index.tsx
访问方式:localhost:3000/about
- pages
- news
- hot.tsx
访问方式:localhost:3000/news/hot
动态路由
动态路由使用方括号包裹参数
- pages
- news
- [newId].tsx
在访问路径的时候加入路由:localhost:3000/news/1
通过useRouter路由钩子获取到路由参数:
1 | const router = useRouter(); |
作为路径的目录名也可以用动态参数的方式命名,
表示父级路径
- pages
- news
- [newsId]
- index.tsx
- comment.tsx(访问目标)
在访问路径的时候加入路由:localhost:3000/news/1/comment
路由中不仅仅可以嵌入1个动态参数,可以嵌入多个
- pages
- news
- [newsId]
- index.tsx
- comment
- index.tsx
- [commentId].tsx(访问目标)
在访问路径的时候加入路由:localhost:3000/news/1/comment/1
动态参数还能包含更多信息:
- pages
- about
- […params].tsx
- about
访问路径:localhost:3000/about/1/2/3
参数获取方式(数组格式返回):
1 | const router = useRouter(); |
运行时动态获取数据
1 | export default function Recipe() { |
构建时获取数据预生成静态页面(SSG)
html诞生之时,就是作为一种从服务器端获取的资源(SSR),
但是随着html对灵活性的需求变得越来越大,
越来越多的交互逻辑都被放在了浏览器端执行,于是就衍生出了CSR的模式,
类似于一家餐厅(服务器)贩卖招牌菜(网页),
一开始外卖员(浏览器)来领餐,厨师把菜老老实实做好交到外卖员手里(SSR)
后来发现外卖员的料理水平甚至比厨师还强(浏览器专门负责js的运行和渲染),
于是厨师干脆就只把料理的食材和食谱(js/html/css等其它原料)交给外卖员,叫它现场制作就行了
- SSR:服务器端渲染,动态生成html文件返回给用户
- SSG:服务器端构建,提前生成静态html文件,用户请求时返回
由于SSR模式下的html文件都是由服务器端生成返回的,
爬虫就能直接爬取到其内容中的信息,
在SEO优化方面也有更大的优势,
这是CSR应用不具有的优势,
CSR类似于美食记者(爬虫)
想要来这家餐厅用招牌菜(网页)取材, 却只收到食材和一张食谱,
完全不知道成品是什么样子
服务器端渲染页面,需要在页面中多添加2个异步方法:
- getStaticPaths
- 用于动态路由页面中,判断哪些路由需要进行与渲染
- getStaticProps
- 请求预渲染参数props
- 使用props渲染组件,生成html页面
页面组件接收一个采纳数props,
而这个参数由getStaticProps传入
1 | export default function Recipe(props:any) { |
在getStaticProps中获取动态数据,传入组件内,调用组件函数进行渲染:
1 | export async function getStaticProps(){ |
对于动态路由页面,无法直接在getStaticProps函数中,通过useRouter直接获取到路由参数,
因此需要用getStaticPaths,定义静态页面生成的范围,
并将路由参信息通过context传入getStaticProps中:
getStaticPaths → getStaticProps → CompFunction
getStaticPaths:
1 | export async function getStaticPaths(){ |
getStaticProps:
1 | // getStaticProps函数名称固定 |
路由跳转 && 数据预取
- Link
- useRouter
1 | export default function RouterButton(){ |
客户请求时按需生成静态页面
动态路由可以进行全量构建:
1 | export async function getStaticPaths(){ |
也可以按需生成,配置getStaticPaths返回fallback为true:
1 | export async function getStaticPaths(){ |
fallback可以有几个值:
- block 访问未生成静态页面的动态路由时,返回404
- true 按需生成静态页面
增量更新内容静态生成页面
getStaticProps返回的revalidate,
用于控制静态页面刷新周期,
1 | export async function getStaticProps(){ |
设置revalidate之后,静态文件的html请求头中就会多出一个参数,
代表缓存时长控制
1 | cache-control: s-maxage=30, stale-while-revalidate |
服务端渲染 SSR
Next中在组件内使用异步方法getServerSideProps,来表示需要服务器端渲染的页面
和getStaticProps的不同之处在于,
getServerSideProps的router参数context更类似http请求头的格式,
包括req、res、params、query等参数,
并且可以对res进行自定义响应头配置:
1 | export async function getServerSideProps(context:any) { |
和SSG不同,SSR支持通过路由传入任何参数,
传参的方式可以是通过路由传入参数,也可以是通过动态路由传参,
无论是哪一种,在getServerSideProps中都可以通过context获取到
路由文件: products.tsx
url:/products?type=phone&&brand=vivo
获取到的参数context.query:
1 | { type: 'phone', brand: 'vivo' } |
双方括号,表示就算不传params,也会映射到该文件中
路由文件:[[…params]].tsx
url:/products/phone/vivo
获取到的参数context.query:
1 | { params: [ 'phone', 'vivo' ] } |
创建后端API接口
在pages下创建api目录,下面存放路由映射接口,
/pages/api
api目录下创建接口路径:api/products.ts
1 | import {NextApiRequest, NextApiResponse} from "next"; |
handler中,根据字段req.method对请求类型进行判断:
1 | export default async function handler( |
页面全局页面布局设置
Next.js v13推出了App Router作为新的路由解决方案:
1 | - app |
其中template和layout都提供了公共的布局方法,
不同点在于:
- layout,相当于多个子页面共享一个父布局
- template,相当于为多个子页面创建相同的布局
在page或者layout中设置metadata变量,作为对header头的补充或者覆盖设置,
常用来优化SEO搜索引擎
1 | import { Metadata } from 'next' |
Next默认app下的所有pages都是由服务器端渲染的,因此一些React的Hook无法使用,
需要在页面的第一行加上注释:
1 | "use client" |
发布到第三方托管平台
将静态文件托管在Vercel平台的方法虽然很简单,
但是国内基本是无法访问到Vercle托管的站点的
部署问题
1 | ReferenceError: document is not defined |
- 页面使用dynamic/ssr引入组件
- 动态引入组件,可以根据ssr的配置判断是否在服务器端引入
- 组件使用use client声明为客户端组件
1 | import dynamic from "next/dynamic" |
1 | "use client" |
NextJs开发文档
目录结构
API参考
函数Function
generateMetadata
参考文章:
next定义静态页面的metadata:
1 | // metadata 头部元数据设置 |