next.js实战记录

577 阅读3分钟

基础知识

渲染方式

next.js 有两种预渲染方式:

  • 编译时渲染 SSG(Static Site Generation)
    • 升级版 ISR(Incremental Static Regeneration)
  • 服务端渲染 SSR(Server Side Rendering)

SSG 通过 getStaticProps 来实现,html页面会在编译时生成,如果具有动态参数的静态页面(即该组件对应的静态页面需要渲染多次),还需要配合 getStaticPaths 来生成。可以通过 revalidate 参数来指定页面有效期,超时将重新生成静态 html 页面。

SSR 通过 getServerSideProps 来实现。其原理是通过 react 的 renderToString/renderToNodeStream 生成 html,然后在客户端调用 ReactDOM.hydrate 来进行事件绑定。

和渲染相关的函数主要有以下几个,只能存在于页面组件中:

  • getStaticProps / getStaticPaths:编译时运行,没有相关函数默认是这种
  • getServerSideProps:服务端运行
  • getInitialProps:第一次在服务端运行,后面返回该路由时在客户端运行(暂不知道该函数使用场景)

html文件只在页面刷新时请求,后续页面切换使用本地路由进行切换(同构渲染的方式),只获取对于页面的json数据(我们在进行路由切换时,network中可以看到json数据返回,对应页面的getStaticProps或getServerSideProps的返回)

api模块

next.js 路由除了生成页面之外,也可以进行 api 的开发,pages/api 目录下的任何文件都将作为 API 端点映射到 /api/*,这得益于 next.js 的node运行环境。例如 pages/api 有一个 list.js 文件,那么 /api/list 将是一个接口,list.js 文件需要导出一个默认的处理函数。

export default function handler(req, res) {
  res.status(200).json({ name: 'John Doe' })
}

有了这样一种机制,我们就可以用node的一些库做些事情。在实际开发中,有用到的位置:

  1. 图片下载及加水印的功能:在前端进行文件或者图片过程中,经常会碰到跨域问题,跨域问题配置好后,使用前端下载方式会存在兼容性问题,特别是在移动端(比如默认打开?)。这个使用可以使用next.js api的方式在后端请求后,然后header中加入 Content-Disposition: attachment; filename="xxx.jpeg" 等信息,明确告诉为下载文件。这样的好处既不存在跨域问题,又不存在兼容性问题,若需要图片加水印,我们也可以在api中使用 sharp 库很容易的进行实现。

我们还可以对api进行一些配置,具体可以查看这里。比如当需要使用 formidable 进行 formData 的读取,需要关闭 bodyParser:

export const config = {
  api: {
    bodyParser: false,
  },
}

图片组件及优化

layout处理

_app.tsx

实战记录

如何在页面间传值

传值很简单,可以通过query传值:

router.push({
  pathname: '/test',
  query: {
    id: 123,
    name: "Gary"
  }
})

这样页面跳转之后,不好的地方是我们的url上会多出很多 query 参数:/test?id=123&name=Gary,若用户刷新的话页面 url 不会变,参数还会保留,这是我们需要在读取了参数之后,恢复成纯净的 path 或者删除某些参数,这个时候我们可以使用 next/router 中的浅路由。

function removeQuery(router, keys = undefined) {
  if (!router) {
    return
  }

  const { pathname, query } = router

  let newQuery = undefined
  if (keys && keys.length > 0) {
    newQuery = { ...query }
    keys.forEach((key) => {
      delete newQuery[key]
    })
  }

  // 我们删除了部分或着全部的query后,使用浅路由(对应shallow: true)的方式进行replace
  router.replace({ pathname, query: newQuery }, undefined, { shallow: true })
}

浅路由跳转,不会请求服务端进行页面参数的获取,即对 getStaticProps, getServerSidePropsgetInitialProps 参数的获取。