Next.js是基于react的一个全栈框架,提供的功能和Nuxt.js基本一样。
Next.js主要是为了解决react的如下问题:
Next.js通过将渲染这个过程移动到服务端(将生成DOM放在服务端完成)来解决以上问题,也就是SSR。
初始化项目
bash1 2 3 4
| npx create-next-app@latest project-name
npx create-next-app@latest --typescript project-name
|
目录结构
路由
静态路由
静态路由是指在编译时就确定了路由和其对应的页面文件。
pages下创建文件即可生成对应的路由配置。
动态路由
可以在pages目录下创建文件名,文件名是变量的形式[param].ts
。
比如,如果想获取一个article页面的参数id,可以在article下定义名为[id].ts
的文件,然后在这个文件内可以使用useRouter
来获取id。
API静态路由
API路由允许我们再next.js项目章自定义服务端逻辑,可以处理客户端发起的http请求。
创建方法:
在pages/api
下创建一个文件,文件名即为路由,这里创建了user.ts
文件。
在user.ts
中编写处理请求的代码。
user.ts1 2 3 4 5 6 7 8 9 10 11 12 13 14
| import type { NextApiRequest, NextApiResponse } from 'next'
type Data = { code: number users: string[] }
export default function handler(req: NextApiRequest, res: NextApiResponse<Data>) { const users: string[] = ['Alice', 'Bob', 'Charlie'] res.status(200).json({ code: 0, users, }) }
|
- 最后访问地址为
/api/user
的API即可获取到数据。
API动态路由
除了上面的静态路由,next.js还可以实现动态路由(也就是在路由中允许参数)。
创建方法:
在pages/api
下创建一个文件,文件名形如[id].ts
,文件名即为路由。
在[id].ts
中编写处理请求的代码,在代码中可以获取到id
。
[id].ts1 2 3 4 5 6 7 8 9 10
| import type { NextApiRequest, NextApiResponse } from 'next'
type Data = { message: string }
export default function handler(req: NextApiRequest, res: NextApiResponse<Data>) { const { id } = req.query res.status(200).json({ message: Received request for ID: ${id} }) }
|
- 最后访问地址为
/api/:id
的API即可获取到对应id的数据。
SSR & SSG
这里有3个重要的方法。
getServerSideProps:服务端渲染,在请求时运行
getStaticProps:服务端生成,生成静态页面时运行
getStaticPaths:服务端生成,生成静态页面时运行
声明SSR页面
在页面组件内添加一个getServerSideProps
函数。
jsx1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| // 正常的页面组件 const Post = ({data}) => { return <div>{ data }</div> }
export default Post
// 将该页面声明为SSR页面,下方函数是在服务端执行的 export async function getServerSideProps(context) { // 取出id const { id } = context.query
// 根据id查询接口 const res = await fetch(`/article/${id}`).then(data => data.json())
return { // 这里的props会被传入到上方组件中 props: { data: res, }, } }
|
声明SSG页面
如果将以上代码的getServerSideProps
改为getStaticProps
,那么代码会在build的时候运行,此时文件会变为在build时渲染出来。
但是我们不知道用户会访问哪个id,所以需要搭配getStaticPaths
来使用,getStaticPaths就是用来枚举用户可能访问的id。
下面生成一些用户可能访问的id:
jsx1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37
| // 正常的页面组件 const Post = ({data}) => { return <div>{ data }</div> }
export default Post
// 将该页面声明为SSR页面,下方函数是在服务端执行的 export async function getStaticProps(context) { // 取出id const { id } = context.query
// 根据id查询接口 const res = await fetch(`/article/${id}`).then(data => data.json())
return { // 这里的props会被传入到上方组件中 props: { data: res, }, } }
// 下面会在build阶段生成id从1到100的页面 export async function getStaticPaths() { return { paths: _.range(1, 100).map((id) => { return { params: { id: id + '', }, } }) // id未命中时退化为SSR fallback: 'blocking', } }
|
fallback
的取值还有:false(404),true(退化到CSR)。
增量静态生成(ISR)
自动重新生成
添加revalidate
参数,表示这个静态页面最多可存活的秒数,如果当用户请求页面时这个页面已经生成了超过10s则会重新生成该页面。可以用来保证静态页面是最新的。
jsx1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39
| // 正常的页面组件 const Post = ({data}) => { return <div>{ data }</div> }
export default Post
// 将该页面声明为SSR页面,下方函数是在服务端执行的 export async function getStaticProps(context) { // 取出id const { id } = context.query
// 根据id查询接口 const res = await fetch(`/article/${id}`).then(data => data.json())
return { // 这里的props会被传入到上方组件中 props: { data: res, }, // 最多存活10s revalidate: 10, } }
// 下面会在build阶段生成id从1到100的页面 export async function getStaticPaths() { return { paths: _.range(1, 100).map((id) => { return { params: { id: id + '', }, } }) // id未命中时退化为SSR fallback: 'blocking', } }
|
手动重新生成
在pages/api
目录下创建一个文件,文件名即路由,在文件中手动调用revalidate
方法即可。
参考
- https://nextjs.frontendx.cn/
- https://www.nextjs.cn/