React服务器渲染框架Next.js

1,469 阅读6分钟

Next.js的简介

  • Next.js 是一个轻量级的React服务器渲染应用框架
  • 完善的React项目架构,搭建轻松。比如:Webpack配置,服务器启动,路由配置,缓存能力,这些在它内部已经完善的为我们搭建完成了。
  • 自带数据同步策略,解决服务端渲染最大难点。把服务端渲染好的数据,拿到客户端重用,这个在没有框架的时候,是非常复杂和困难的。有了Next.js,它为我们提供了非常好的解决方法,让我们轻松的就可以实现这些步骤。
  • 灵活的配置,让开发变的更简单。它提供很多灵活的配置项,可以根据项目要求的不同快速灵活的进行配置。
  • 目前Next.js是React服务端渲染的最佳解决方案,所以如果你想使用React来开发需要SEO的应用,基本上就要使用Next.js。

优点

  • 有了Next.js以后我们可以简单轻松的实现React的服务端渲染,从而加快首屏打开速度,也可以作SEO(搜索引擎优化了)。
  • 在没有Next.js的时候,用React开发需要配置很多繁琐的参数,如Webpack配置,Router配置和服务器端配置等....。
  • 如果需要作SEO,要考虑的事情就更多了,怎么样服务端渲染和客户端渲染保持一致就是一件非常麻烦的事情,需要引入很多第三方库。
  • 但有了Next.js,这些问题都解决了,使开发人员可以将精力放在业务逻辑上

创建Next.js项目

手动创建

1. npm init  // 在根目录里给你添加了一个package.json的文件
2. npm install --save react react-dom next // 安装所需要的依赖包
3. "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "dev" : "next" ,
    "build" : " next build",
    "start" : "next start"
  } // 配置package.json,增加快捷命令
4. 创建pages 文件夹(这个文件夹名字是next规定的)next.js 会自动创建对应的路由,创建文件夹后(index.js) 使用/index 即可访问
5. npm run dev // 运行 
运行 npm run dev 命令并打开 http://localhost:3000。 
如果你想使用其他端口,可运行 npm run dev -- -p <设置端口号>.`npm run dev -- -p 3080`:ready - started server on http://localhost:3080
 npm run dev -- -p 3080

> next.js@1.0.0 dev /Users/mavis/gitHub/2020_react/next.js-demo
> next

ready - started server on http://localhost:3080
(node:43465) ExperimentalWarning: The fs.promises API is experimental
event - compiled successfully

create-next-app(脚手架)来创建

npx 是Node自带的npm模块,所以你只要安装了Node都是可以直接使用npx命令的。

1. npm install -g npx// 安装全局next.js
2. npx create-next-app next-create // 创建项目
3. npm run dev // 运行

项目结构介绍

  • components 放置公共组建(不包括页面)
  • node_modules 依赖包
  • pages 这里是放置静态文件的,一些页面,这里的内容会自动生成路由,并在服务端渲染,渲染好后会数据同步
  • static 静态文件夹,放一些图片和静态资源
  • .gitignore 忽略提交Git上传文件
  • package.json 文件的配置信息(名称,版本,许可证)最主要的是用来npm install 下载依赖包

 create-next-app结构

路由-基础和基本跳转

1. Link 和 Router

import React from 'react'
import Link from 'next/link'
import Router from 'next/router'

const Home = () => {
  function gotoA() {
    Router.push({
      pathname: '/IndexB',
      query: {
        name: 'ldd'
      }
    })
  }
  return (
    <div>
      <div>我是首页</div>
      {/* Link链接不支持兄弟标签 */}
      <div><Link href="/indexA?name=小白"><a>去IndexA页面</a></Link></div>
      <div><button onClick={gotoA}>去IndexB页面</button></div>
    </div>
  )
}

export default Home

2. 传值和接收参数

接收传递过来的参数 在Next.js中只能通过通过query(?id=1)来传递参数,而不能通过(path:id)的形式传递参数

import Link from 'next/link'
import { withRouter} from 'next/router' // 是next的高阶组件,用来处理路由的

const IndexA = ({router})=>(
    <div>
        <div>Index-A page.  name:{router.query.name}</div>
        <Link href="/"><a>返回首页</a></Link>
    </div>
)

export default withRouter(IndexA)

3. 路由的六个钩子事件

路由的钩子事件,就是当路由发生改变的时候,可以监听到这些事件, Router.events.on() 用来监听事件

import Router from 'next/router'
import { withRouter} from 'next/router'

const routerChange = ({ router }) => {
    Router.events.on('routeChangeStart', (...args) => {
        console.log('1.routeChangeStart->路由开始变化,参数为:', ...args)
    })

    Router.events.on('routeChangeComplete', (...args) => {
        console.log('2.routeChangeComplete->路由结束变化,参数为:', ...args)
    })

    Router.events.on('beforeHistoryChange', (...args) => {
        console.log('3.beforeHistoryChange->在改变浏览器 history之前触发,参数为:', ...args)
    })

    Router.events.on('routeChangeError', (...args) => {
        console.log('4.routeChangeError->跳转发生错误,参数为:', ...args)
    })

    Router.events.on('hashChangeStart', (...args) => {
        console.log('5.hashChangeStart->hash跳转开始时执行,参数为:', ...args)
    })

    Router.events.on('hashChangeComplete', (...args) => {
        console.log('6.hashChangeComplete->hash跳转完成时,参数为:', ...args)
    })
    return (
        <div>
            routerChange页面<br />
            <Link href="/"><a>返回首页</a></Link><br />
            <div>
                <Link href="#hash"><a>hash</a></Link>
            </div>
            <div>
                <Link href="/indexA?name=ldd"><a>indexA</a></Link>
            </div>
        </div>
    )
}

export default routerChange

使用getInitialProps中的Axios获取数据

Next.js 提供了getInitialProps静态方法来获取数据,不用在componentDidMount中获取数据了,getInitialProps 是Next.js最伟大的发明,它确定了一种Next.js的一种规范,是next.js自己定义的一个新的生命周期,并且在不影响react的生命周期以外的一个扩展方法,getInitialProps 是一个async函数,所以在getInitialProps函数中可以使用await关键字,用同步方式编程异步逻辑

routerChange.getInitialProps = async () => {
    const promise = new Promise((resolve) => {
        axios('https://www.easy-mock.com/mock/5dc0d5b143ff8e61fd932abe/example/query').then(
            (res) => {
                console.log('远程数据结果:', res)
                resolve(res.data.data)
            }
        )
    })
    return await promise
}

使用Style JSX语法和Antd 编写语法

1. style

next.js 是不支持 css的,所以不能用 import来引入,如果要用的话,需要另外配置(b. 会讲解如何配置)

import Link from 'next/link'
import { withRouter } from 'next/router'

const IndexA = ({ router }) => (
    <div>
        <div className="name">Index-A page .  name:{router.query.name}</div>
		<p>这是一段文字,很长的一段文字。。。。。</p>
        <Link href="/"><a>返回首页</a></Link>
        <style jsx>
            {
                `
                    .name {
                        color: red;
                    }


					p {
                        background: pink;
                    }
                `
            }
        </style>
    </div>
)

export default withRouter(IndexA)

使用Style JSX的话 next.js 会自动给加入一个随机的类名

2. 配置css

1.yarn add @zeit/next-css 
2.在根目录下建立一个next.config.js 代码如下,这个是next.js的总配置文件 
3.重启代码运行即可

按需加载Ant Design 加载Ant Design在我们打包的时候会把Ant Design的所有包都打包进来,这样就会产生性能问题,让项目加载变的非常慢。这肯定是不行的,现在的目的是只加载项目中用到的模块,这就需要我们用到一个babel-plugin-import文件。安装完成后,在项目根目录建立.babelrc文件

1. yarn add antd
2. yarn add babel-plugin-import
3. 在项目根目录建立.babelrc文件
   {
    "presets":["next/babel"],  // Next.js的总配置文件,相当于继承了它本身的所有配置
    "plugins":[     // 增加新的插件,这个插件就是让antd可以按需引入,包括CSS
        [
            "import",
            {
                "libraryName":"antd",
                "style":"css"
            }
        ]
    ]
  }

这样配置好了以后,webpack就不会默认把整个Ant Design的包都进行打包到生产环境了,而是我们使用那个组件就打包那个组件,同样CSS也是按需打包的。

通过上面的配置,就可以愉快的在Next.js中使用Ant Desgin,让页面变的好看起来。

自定义<Head> 更加友好的SEO操作

1. 方法一:在各个页面上加<Head>

在pages文件下创建个header.js

import React from 'react';
import Head from 'next/head';

 const Header = ()=>(
    <div>
        <Head>
            <title>学习Next.js</title>
            <meta charSet='utf-8' />
        </Head>
        <div>Next.js 是一个轻量级的 React 服务端渲染应用框架。</div>
    </div>
)

export default Header