1.Next.js简介
Next.js 是一个轻量级的 React 服务端渲染应用框架。
它的优点:
- 完善的React项目架构,搭建轻松。比如:Webpack配置,服务器启动,路由配置,缓存能力,这些在它内部已经完善的为我们搭建完成了。
- 自带数据同步策略,解决服务端渲染最大难点。把服务端渲染好的数据,拿到客户端重用,这个在没有框架的时候,是非常复杂和困难的。有了Next.js,它为我们提供了非常好的解决方法,让我们轻松的就可以实现这些步骤。
- 丰富的插件帮开发人员增加各种功能。每个项目的需求都是不一样的,包罗万象。无所不有,它为我们提供了插件机制,让我们可以在使用的时候按需使用。你也可以自己写一个插件,让别人来使用。
- 灵活的配置,让开发变的更简单。它提供很多灵活的配置项,可以根据项目要求的不同快速灵活的进行配置。
2.快速创建Next.js
#全局安装
npm install -g create-next-app
#npx创建项目
npx install create-next-app demo13
cd demo13
#本地运行
yarn dev
3.项目结构介绍
- components文件夹:这里是专门放置自己写的组件的,这里的组件不包括页面,指公用的或者有专门用途的组件。
- node_modules文件夹:Next项目的所有依赖包都在这里,一般我们不会修改和编辑这里的内容。
- pages文件夹:这里是放置页面的,这里边的内容会自动生成路由,并在服务器端渲染,渲染好后进行数据同步。
- static文件夹: 这个是静态文件夹,比如项目需要的图片、图标和静态资源都可以放到这里。
- .gitignore文件: 这个主要是控制git提交和上传文件的,简称就是忽略提交。
- package.json文件:定义了项目所需要的文件和项目的配置信息(名称、版本和许可证),最主要的是使用
npm install
就可以下载项目所需要的所有包。
4.Page和Component使用
在pages文件下,创建Test.js。
function Test(){
return (<button> Test page</button>)
}
export default Test;
写完以上的代码,Next
框架就自动作好了路由,这个也算是Next的一个重要优点,给我们节省了大量的时间。
现在要作一个更深的页面,比如把有关博客的界面都放在这样的路径下http://localhost:3000/blog/nextBlog
,其实只要在pages
文件夹下再建立一个新的文件夹blog
,然后进入blog
文件夹,新建一个nextBlog.js
文件,就可以实现了。
编写组件也特别方便,比如要建立一个comm组件,直接在components
目录下建立一个文件comm,然后写入下面代码:
export default ({children})=><button>{children}</button>
组件写完后需要先引入,比如我们在Index页面里进行引入:
import comm from '../components/comm'
使用就非常简单了,直接写入标签就可以。
<comm>按钮</comm>
5.路由基础及跳转
5.1 标签是导航
首先先删除index.js中的代码,引入以下:
import Link from 'next/link'
然后新建两个页面testA.js
和testB.js
import Link from 'next/link'
export default ()=>(
<>
<div>TestA page . </div>
<Link href="/"><a>返回首页</a></Link>
</>
)
import Link from 'next/link'
export default ()=>(
<>
<div>TestB page . </div>
<Link href="/"><a>返回首页</a></Link>
</>
)
然后编写index文件
import React from 'react'
import Link from 'next/link'
const Home = () => (
<>
<div>我是首页</div>
<div><Link href="/testA"><a>去testA页面</a></Link></div>
<div><Link href="/testB"><a>去testB页面</a></Link></div>
</>
)
export default Home
注意:不支持兄弟并列标签。
5.2 Router模块跳转
在index.js中,添加以下:
<div>
<button onClick={()=>{Router.push('/testA')}}>去testA页面</button>
</div>
6.路由跳转传值和接收参数
6.1 query传递参数及接收
<div><Link href="/testA?name=karma"><a>Link跳转去testA页面</a></Link></div>
//或
<div><Link href={{pathname: '/testA', query: {name: 'karma'}}}><a>Link跳转去testA页面</a></Link></div>
然后在testA.js文件中接收该参数:
import React from 'react'
import Link from 'next/link'
import {withRouter} from "next/router";
const testA = ({router}) => (
<>
<div>testA page . {router.query.name}</div>
<Link href="/"><a>返回首页</a></Link>
</>
)
//withRouter是Next.js框架的高级组件,用来处理路由用的
export default withRouter(testA)
6.2 Router编程式传递参数
<button onClick={()=>{Router.push('/testA?name=karma')}}>去testA页面</button>
#或者
<button onClick={()=>{Router.push({
pathname:'/testA',
query:{
name:'karma'
}
})}>去testA页面</button>
7.路由-六个钩子事件
routerChangeStart
路由发生变化
Router.events.on('routeChangeStart',(...args)=>{
console.log('1.routeChangeStart->路由开始变化,参数为:',...args)
})
routerChangeComplete
路由结束变化时
Router.events.on('routeChangeComplete',(...args)=>{
console.log('routeChangeComplete->路由结束变化,参数为:',...args)
})
beforeHistoryChange
浏览器history触发前
Router.events.on('beforeHistoryChange',(...args)=>{
console.log('3,beforeHistoryChange->在改变浏览器 history之前触发,参数为:',...args)
})
routeChangeError
路由跳转发生错误时
Router.events.on('routeChangeError',(...args)=>{
console.log('4,routeChangeError->跳转发生错误,参数为:',...args)
})
需要注意的是404找不到路由页面不算错误。
转变成hash路由模式
还有两种事件,都是针对hash的,所以现在要转变成hash模式。hash模式下的两个事件hashChangeStart
和`hashChangeComplete。
Router.events.on('hashChangeStart',(...args)=>{
console.log('5,hashChangeStart->hash跳转开始时执行,参数为:',...args)
})
Router.events.on('hashChangeComplete',(...args)=>{
console.log('6,hashChangeComplete->hash跳转完成时,参数为:',...args)
})
在下面的jsx语法部分,再增加一个链接,使用hash来进行跳转,代码如下:
<div>
<Link href="#test"><a>test</a></Link>
</div>
8.在getInitialProps中使用Axios获取远端数据
在Next.js
框架中提供了getInitialProps
静态方法用来获取远端数据,这个是框架的约定,所以你也只能在这个方法里获取远端数据。
安装Axios:
yarn add axios
在testA.js中引入Axios
import Axios from 'axios'
然后使用getInitialProps获取远程数据并渲染页面
import React from 'react'
import Link from 'next/link'
import {withRouter} from "next/router";
import Axios from "axios";
const testA = ({router, list}) => (
<>
<div>testA page . {router.query.name} {list}</div>
<Link href="/"><a>返回首页</a></Link>
</>
)
testA.getInitialProps = async () => {
const promise = new Promise((resolve => {
Axios('https://www.easy-mock.com/mock/5f96cc6134c55d14fda96ea1/example/query').then((res) => {
console.log('远程数据结果:', res)
resolve(res.data.data)
})
}))
return await promise
}
//withRouter是Next.js框架的高级组件,用来处理路由用的
export default withRouter(testA)
9.使用style JSX编写页面的css样式
在pages文件下,创建testC.js.
function testC(){
return (
<>
<div>testC</div>
<style jsx>
{`
div{color:blue;}
`}
</style>
</>
)
}
export default testC
通过自定义类名加载css
function testC(){
return (
<>
<div>testC</div>
<div className="karma">karma</div>
<style jsx>
{`
div{color:blue;},
.karma{color:red}
`}
</style>
</>
)
}
export default testC
动态显示样式
import {useState} from "react";
function testC() {
const [color, setColor] = useState('blue')
const changeColor = () => {
setColor(color === 'blue' ? 'red' : 'blue')
}
return (
<>
<div>testC</div>
<div>
<button onClick={changeColor}>改变颜色</button>
</div>
<div className="karma">karma</div>
{/*Style JSX语法*/}
<style jsx>
{`
div{color:${color};},
`}
</style>
</>
)
}
export default testC
10.Lazy Loading 实现模块懒加载
懒加载模块
安装moment
yarn add moment
然后在pages
文件夹下,新建立一个time.js
文件,并使用刚才的moment
库来格式化时间,代码如下:
import React, {useState} from 'react'
import moment from 'moment'
function Time(){
const [nowTime,setTime] = useState(Date.now())
const changeTime=()=>{
setTime(moment(Date.now()).format())
}
return (
<>
<div>显示时间为:{nowTime}</div>
<div><button onClick={changeTime}>改变时间格式</button></div>
</>
)
}
export default Time
这个案例,存在着一个潜在的风险,就是如何有半数以上页面使用了这个momnet
的库,那它就会以公共库的形式进行打包发布,就算项目第一个页面不使用moment
也会进行加载,这就是资源浪费,对于我这样有代码洁癖的良好程序员是绝对不允许的。下面我们就通过Lazy Loading
来进行改造代码。
import React, {useState} from 'react'
//删除import moment
function Time(){
const [nowTime,setTime] = useState(Date.now())
const changeTime= async ()=>{ //把方法变成异步模式
const moment = await import('moment') //等待moment加载完成
setTime(moment.default(Date.now()).format()) //注意使用defalut
}
return (
<>
<div>显示时间为:{nowTime}</div>
<div><button onClick={changeTime}>改变时间格式</button></div>
</>
)
}
export default Time
懒加载自定义组件
先写一个最简单的组件,在components
文件夹下建立一个one.js
文件,然后编写如下代码:
export default ()=><div>Lazy Loading Component</div>
有了自定义组件后,先要在懒加载这个组件的文件中引入dynamic
,我们这个就在上边新建的time.js
文件中编写了。
import dynamic from 'next/dynamic'
引入后就可以懒加载自定义模块了,代码如下:
import React, {useState} from 'react'
import dynamic from 'next/dynamic'
const One = dynamic(import('../components/one'))
function Time(){
const [nowTime,setTime] = useState(Date.now())
const changeTime= async ()=>{
const moment = await import('moment')
setTime(moment.default(Date.now()).format())
}
return (
<>
<div>显示时间为:{nowTime}</div>
<One/>
<div><button onClick={changeTime}>改变时间格式</button></div>
</>
)
}
export default Time
11.自定义Head更加友好的SEO操作
一般有两种方式。
方法1:在各页面加上标签
先在/pages
文件夹下面建立一个header.js
文件,然后写一个最简单的Hooks
页面,代码如下:
function Header(){
return (<div>JSPang.com</div>)
}
export default Header
写完后到浏览器中预览一下,可以发现title部分并没有任何内容,显示的是localhost:3000/header
,接下来就自定义下<Head>
。自定义需要先进行引入next/head
。
import Head from 'next/head'
引入后你就可以写一些列的头部标签了,全部代码如下:
import Head from 'next/head'
function Header(){
return (
<>
<Head>
<title>Header</title>
<meta charSet='utf-8' />
</Head>
<div>Karma520.com</div>
</>
)
}
export default Header
这时候再打开浏览器预览,你发现已经有了title
。
方法2:全局定义
比如在components
文件夹下面新建立一个myheader.js
,然后写入下面的代码:
import Head from 'next/head'
const MyHeader = ()=>{
return (
<>
<Head>
<title> Karma520.com </title>
</Head>
</>
)
}
export default MyHeader
把刚才编写的header.js
页面改写一下,引入自定义的myheader
,在页面里进行使用。
import Myheader from '../components/myheader'
function Header(){
return (
<>
<Myheader />
<div>Karma520.com</div>
</>
)
}
export default Header
12.Next.js脚手架中使用Ant Design UI
Next.js
默认是不支持CSS文件的,它用的是style jsx
,也就是说它是不支持直接用import
进行引入css
的。
在static下新建一个test.css
文件,写入一些CSS Style
。
body{
color:green;
}
然后用import
在header.js
里引入。
import '../static/test.css'
写完到浏览器中进行预览,没有任何输出结果而且报错了。这说明Next.js
默认是不支持CSS样式引入的,要进行一些必要的设置,才可以完成。
开始进行配置,让Next.js支持CSS文件
先用yarn
命令来安装@zeit/next-css
包,它的主要功能就是让Next.js
可以加载CSS文件。
yarn add @zeit/next-css
包安装好以后就可以进行配置文件的编写了,建立一个next.config.js
.这个就是Next.js
的总配置文件(如果感兴趣可以自学一下)。
const withCss = require('@zeit/next-css')
if(typeof require !== 'undefined'){
require.extensions['.css']=file=>{}
}
module.exports = withCss({})
重启服务可以让配置生效,这时候你到浏览器中可以发现CSS文件已经生效了,字变成了绿色。
按需加载Ant Design
加载Ant Design
在我们打包的时候会把Ant Design
的所有包都打包进来,这样就会产生性能问题,让项目加载变的非常慢。
** 先来安装Ant Design
库 **
直接使用yarn来安装就可以。
yarn add antd
** 安装和配置babel-plugin-import
插件 **
yarn add babel-plugin-import
然后在项目根目录建立.babelrc
文件,然后写入如下配置文件。
{
"presets":["next/babel"], //Next.js的总配置文件,相当于继承了它本身的所有配置
"plugins":[ //增加新的插件,这个插件就是让antd可以按需引入,包括CSS
[
"import",
{
"libraryName":"antd",
"style":"css"
}
]
]
}
配置好了以后,webpack
就不会默认把整个Ant Design
的包都进行打包到生产环境了,而是我们使用那个组件就打包那个组件,同样CSS也是按需打包的。
然后在header.js里,引入<Button>
组件,并进行使用。
import Myheader from '../components/myheader'
import {Button} from 'antd'
import '../static/test.css'
function Header(){
return (
<>
<Myheader />
<div>Karma520.com</div>
<div><Button>按钮</Button></div>
</>
)
}
export default Header
运行,看效果。
13.Next打包CSS问题
打包 :yarn build
然后在终端里运行一下yarn build
,如果这时候报错,其实是我们在加入Ant Design
的样式时产生的,这个已经在Ant Design
的Github上被提出了,但目前还没有被修改,你可以改完全局引入CSS解决问题。
在page目录下,修改_app.js
文件。
import App from 'next/app'
import 'antd/dist/antd.css'
export default App
并且注释.babelrc中该行配置 “style”:”css”,然后执行命令。
源码地址:传送门
本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!