Next.js 入门

欢迎关注我的公众号睿Talk,获取我最新的文章:
clipboard.png

一、前言

当使用 React 开发系统的时候,常常需要配置很多繁琐的参数,如 Webpack 配置、Router 配置和服务器配置等。如果需要做 SEO,要考虑的事情就更多了,怎么让服务端渲染和客户端渲染保持一致是一件很麻烦的事情,需要引入很多第三方库。针对这些问题,Next.js提供了一个很好的解决方案,使开发人员可以将精力放在业务上,从繁琐的配置中解放出来。下面我们一起来看看它的一些特性。

二、特性介绍

Next.js 具有以下几点特性:

  • 默认支持服务端渲染
  • 自动根据页面进行代码分割
  • 简洁的客户端路由方案(基于页面)
  • 基于 Webpack 的开发环境,支持热模块替换
  • 可以跟 Express 或者其它 Node.js 服务器完美集成
  • 支持 Babel 和 Webpack 的配置项定制

三、Hello World

执行以下命令,开始 Next.js 之旅:

mkdir hello-next
cd hello-next
npm init -y
npm install --save react react-dom next
mkdir pages

package.json中输入以下内容:

{
  "scripts": {
    "dev": "next",
    "build": "next build",
    "start": "next start"
  }
}

在 pages 文件夹下,新建一个文件 index.js

const Index = () => (
  

Hello Next.js

) export default Index

在控制台输入npm run dev,这时候在浏览器输入http://localhost:3000,就能看到效果了。

Next.js 入门_第1张图片

四、路由

Next.js 没有路由配置文件,路由的规则跟 PHP 有点像。只要在 pages 文件夹下创建的文件,都会默认生成以文件名命名的路由。我们新增一个文件看效果pages/about.js

export default function About() {
  return (
    

This is the about page

) }

在浏览器输入http://localhost:3000/about,就能看到相应页面了。

Next.js 入门_第2张图片

如果需要进行页面导航,就要借助next/link组件,将 index.js 改写:

import Link from 'next/link'

const Index = () => (
  
About Page

Hello Next.js

) export default Index

这时候就能通过点击链接进行导航了。

如果需要给路由传参数,则使用query string的形式:

 
   About Page
 

取参数的时候,需要借助框架提供的withRouter方法,参数封装在 query 对象中:

import { withRouter } from 'next/router'

const Page = withRouter(props => (
  

{props.router.query.title}

)) export default Page

如果希望浏览器地址栏不显示query string,可以使用as属性:

{props.title}

这时候浏览器会显示这样的url:localhost:3000/p/12345

五、SSR

Next.js 对服务端渲染做了封装,只要遵守一些简单的约定,就能实现 SSR 功能,减少了大量配置服务器的时间。以上面这个 url 为例子,直接在浏览器输入localhost:3000/p/12345是会返回404的,我们需要自己实现服务端路由处理的逻辑。下面以express为例子进行讲解。新建一个 server.js 文件:

const express = require('express')
const next = require('next')

const dev = process.env.NODE_ENV !== 'production'
const app = next({ dev })
const handle = app.getRequestHandler()

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

    // 处理localhost:3000/p/12345路由的代码
    server.get('/p/:id', (req, res) => {
      const actualPage = '/post'
      const queryParams = { title: req.params.id }
      app.render(req, res, actualPage, queryParams)
    })

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

    server.listen(3000, err => {
      if (err) throw err
      console.log('> Ready on http://localhost:3000')
    })
  })
  .catch(ex => {
    console.error(ex.stack)
    process.exit(1)
  })

当遇到/p/:id这种路由的时候,会调用app.render方法渲染页面,其它的路由则调用app.getRequestHandler方法。

无论是服务端渲染还是客户端渲染,往往都需要发起网络请求获取展示数据。如果要同时考虑 2 种渲染场景,可以用getInitialProps这个方法:

import Layout from '../components/MyLayout.js'
import fetch from 'isomorphic-unfetch'

const Post = props => (
  
    

{props.show.name}

{props.show.summary.replace(/<[/]?p>/g, '')}

) Post.getInitialProps = async function(context) { const { id } = context.query const res = await fetch(`https://api.tvmaze.com/shows/${id}`) const show = await res.json() console.log(`Fetched show: ${show.name}`) return { show } } export default Post

获取数据后,组件的props就能获取到getInitialProps return 的对象,render 的时候就能直接使用了。getInitialProps是组件的静态方法,无论服务端渲染还是客户端渲染都会调用。如果需要获取 url 带过来的参数,可以从context.query里面取。

六、CSS in JS

对于页面样式,Next.js 官方推荐使用 CSS in JS 的方式,并且内置了styled-jsx。用法如下:

import Layout from '../components/MyLayout.js'
import Link from 'next/link'

function getPosts() {
  return [
    { id: 'hello-nextjs', title: 'Hello Next.js' },
    { id: 'learn-nextjs', title: 'Learn Next.js is awesome' },
    { id: 'deploy-nextjs', title: 'Deploy apps with ZEIT' }
  ]
}

export default function Blog() {
  return (
    
      

My Blog

) }

注意