nextjs踩坑

Next.js踩坑

险些一全年没咋写文章,主假如懒,加上事情也挺忙。然则想趁着岁尾发一篇,愿望来岁更用功一点。着实不是没东西写,就是想深切一个东西照样很难题的,要查种种材料,终究照样懒就是了。

next.js是react的同构库,许多文章里把他看成一个脚手架,也不是不可,然则个人以为next.js比平常的脚手架能做的更多,但也有局限性。这两天放工归去实践了一下nextjs的开辟。碰到一些坑,也有一些收成这里纪录一下。

要求数据

nextjs没有客户端的性命周期,只要一个静态要领getInitialProps,所以猎取接口数据也只能在这个要领里了。getInitialProps的返回数据就作为该组件的props。getInitialProps有两个参数:req和res,也就是我们异常熟习的http参数。说句题外话,现有的node web框架都是req作为输入,res作为输出,增添种种中间件。

所以个人以为nextjs的组件情势太合适无状况组件了。下面是一个简朴的例子代码:

// 猎取影戏列表并衬着
class MovieList extends Component {
    static async getInitialProps(){
      const data = await getMovieList()
    return {
        list: data
    }
  }
  
  render () {
      return (
        <div>
        {this.props.list.map(movie => {
            <MovieCard key={movie.id} movie={movie}>
        })}
      </div>
    )
  }
}

固然这里终究仅仅是效劳端输出的列表,我们能够还会有其他操纵,比方删除加载下一页之类的,然则这些操纵都没必要在效劳端操纵的。增加几个响应的要领即可。

路由治理

nextjs的路由是基于文件体系的,相称清楚和简朴,比方在pages文件夹下面增添一个movie-detail组件,并写上响应的代码,我们就能够接见/movie-detail 这个路由了。早先以为如许的路由情势着实太文雅了,然则用久了就会发明许多题目。

路由嵌套

起首是嵌套路由,比方我想竖立/user/profile这个路由,这个着实很好处置惩罚,就是在pages文件夹下面顺次嵌套就好了:

《nextjs踩坑》

签字路由

其次是没有官方完成签字途径,什么是签字途径呢?就是/movie/:id这里这类情势,个人感觉nextjs在这方面是跟随react-router4的。vuejs的同构框架nuxtjs则不存在这个题目,由于vue-router自身也是统一治理路由的。先不说这类状况的优劣,照样找找处置惩罚计划吧。

依据我找到的实例和文档,现在有两种处置惩罚计划:

运用query替代签字路

下图能够看到着实在nextjs router里query是存在的。

《nextjs踩坑》

那我们须要接见签字路由页面的时刻能够这么写, 将id用query传过去/movie-detail?id=xxx

// 影戏概况页面

class MovieDetail extends Component {
    static async getInitialProps({ req }) {
    const { id } = req.query
    const detail = await getDetail(id) 
      return {
        detail
    }
  }
  
  render () {
      return (
        // do anything you want
    )
  }
}

custom server 处置惩罚

运用query传参数过去确切能够处置惩罚题目,然则太不文雅,与rest的头脑也不太相符。所以next社区找到了另一个处置惩罚计划,运用custom server。

在说详细计划之前我们我们能够相识一下,说到底nextjs并非一个天生静态资本的脚手架,next终究照样要零丁布置node效劳的。也就是nextjs着实内置了一个http效劳,假如我们不运用custom sever的话,内置效劳照样能够很好的帮我们完成衬着页面的使命。

然则假如我们的node不单单议是衬着页面,还须要写接口。那末这时刻的状况就很相似传统后端的开辟形式了:不单单议须要写接口还须要衬着页面。

很显然nextjs的内置http效劳是没法完成这个使命的,我们须要越发完美的web 框架。毕竟专业的事照样交给专业的。这时刻就是custom server大显神通的时刻了。nextjs里也有一系列的例子:
《nextjs踩坑》

那末custom server是怎样处置惩罚签字途径的题目的呢?我们是借用nextjs的衬着才能。这里以express为例,详细代码以下:

// server.js
const express = require('express')
const next = require('next')

const dev = process.env.NODE_ENV !== 'production'
const app = next({ dev, quiet: false })
const handle = app.getRequestHandler()
const SERVE_PORT = process.env.SERVE_PORT || 8001

app.prepare().then(() => {
  const server = express()

  server.get('/movie-detail/:id', async (req, res) => {
    // 衬着movie-detail这个组件
    const html = await app.renderToHTML(req, res, '/movie-detail', req.query)
    res.send(html)
  })

  server.get('*', (req, res) => handle(req, res))

  server.listen(SERVE_PORT, err => {
    if (err) throw err
    console.log(`> Ready on http://localhost:${SERVE_PORT}`)
  })
})

上面是server.js的简单代码,固然在组件里我们也要做响应处置惩罚,代码以下

// /pages/movie-detail.jsx
// 影戏概况页面

class MovieDetail extends Component {
    static async getInitialProps({ req }) {
    const { id } = req.params
    const detail = await getDetail(id) 
      return {
        detail,
      id
    }
  }
  
  render () {
      return (
        // do anything you want
    )
  }
}

页面缓存

关于csr的的react运用来讲,衬着耗时100ms并非什么太大题目,然则到了效劳端,100ms很明显是没法忍耐的。起首客户端衬着并不会形成效劳器资本的糟蹋,着实也不会对效劳器形成太大鸭梨。然则效劳端就不一样了。一旦用户量大了,必将会引起种种题目,所以页面缓存照样很有必要的。

详细页面缓存在那里并非我们考量的局限,一样页面缓存也须要用到custom server,详细效劳端框架自定吧。这里以lru-cache为例做一个简朴的页面缓存,着实换成其他的诸如redis也是没有任何题目的。

const dev = process.env.NODE_ENV !== 'production'

const next = require('next')
const express = require('express')
const LRUCache = require('lru-cache')

const ssrCache = new LRUCache({
  max: 1000, // cache item count
  maxAge: 1000 * 60 * 60, // 1 hour
})

const app = next({ dev, quiet: false })

const handle = app.getRequestHandler()

const SERVE_PORT = process.env.SERVE_PORT || 8001

app.prepare().then(() => {
  const server = express()

  server.get('/', async (req, res) => {
    renderAndCache(req, res, '/', { ...req.query })    
  })

  server.get('/movie-detail/:id', async (req, res) => {
    renderAndCache(req, res, '/movie-detail', { ...req.query })
  })

  server.get('*', (req, res) => handle(req, res))

  server.listen(SERVE_PORT, err => {
    if (err) throw err
    console.log(`> Ready on http://localhost:${SERVE_PORT}`)
  })
})

const getCacheKey = req => `${req.url}`

// 缓存并衬着页面,详细是从新衬着照样运用缓存
async function renderAndCache(req, res, pagePath, queryParams) {
  const key = getCacheKey(req)
  if (ssrCache.has(key)) {
    res.setHeader('x-cache', 'HIT')
    res.send(ssrCache.get(key))
    return
  }

  try {
    const html = await app.renderToHTML(req, res, pagePath, queryParams)

    // Something is wrong with the request, let's skip the cache
    if (res.statusCode !== 200) {
      res.send(html)
      return
    }

    // Let's cache this page
    ssrCache.set(key, html)

    res.setHeader('x-cache', 'MISS')
    res.send(html)
  } catch (err) {
    app.renderError(err, req, res, pagePath, queryParams)
  }
}

个中renderAndCache是症结。这里推断页面是不是有缓存,假若有的话则直出缓存内容。不然的话就从新衬着。至于缓存时候另有缓存大小视个人设置了,这里不赘述了。

布置上线

布置上线这一块着实没什么好说的,简朴的话直接起一个node效劳的就能够,庞杂一点就要包含报警重启等等,都是看个人状况的。

个人习气运用supervisor启动node效劳。

总结

说了上面那末多,着实官方文档里都有相干例子,就当我的个人踩坑纪录吧。

关于nextjs来讲,我以为假如是展现型的运用,就应该放心大胆的用起来。不光开辟快还爽,同时屏障webpack设置,有什么来由不必?

假如是功能性的,比方一系列的画图组件则完成没必要运用了,关于canvas之类的照样必须用客户端衬着,但是nextjs又没有性命周期,用nextjs能够会相称坑。

关于个人开辟这我则是相称引荐。何必去设置webpack糟蹋性命啊。

假如是完整静态的运用,我引荐gatsbyjs。详细怎样运用则是别的一个话题了。

若有错误,轻点喷。 over

    原文作者:xiadd
    原文地址: https://segmentfault.com/a/1190000018092921
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞