0%

Next.js

Next.js

是什么?

Next.js 是一个轻量级的 React 服务端渲染应用框架。有了它我们可以简单轻松的实现React的服务端渲染,从而加快首屏打开速度,也可以作SEO(收索引擎优化了)。

Next.js官方文档

最初

在没有Next.js的时候,用React开发需要配置很多繁琐的参数,如Webpack配置,Router配置和服务器端配置等….

如果需要作SEO,要考虑的事情就更多了,怎么样服务端渲染和客户端渲染保持一致就是一件非常麻烦的事情,需要引入很多第三方库。但有了Next.js,这些问题都解决了,使开发人员可以将精力放在业务逻辑上!

优点

  1. 搭建轻松
  2. 自带数据同步 SSR
  3. 丰富的插件
  4. 灵活的配置

搭建

  1. 手动配置
  2. 使用create-next-app脚手架配置
  1. 下载所用到的依赖npm i react react-dom next
  2. 修改package.json
1
2
3
4
5
6
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"dev":"next", //项目启动
"build":"next build", //项目打包
"start": "next start" //开启服务
},

1.手动搭建

  • 新建文件pages
  • 新建index.js
1
2
3
4
5
6
function Index() {
return (
<div>Hello Next.js</div>
)
}
export default Index
  • 执行npm run dev启动项目调试

无需引入React就可以使用

2.脚手架

  1. 全局安装 npm i -g create-next-app
  2. 创建基础项目npx create-next-app 项目名字
    • npx create-next-app next-create

image-20220908210825826

项目大致结构如上,正常都知道是干什么的。

注:.eslintrc.json文件是规范书写格式的一个第三方包

Next中的路由

在Next中pages文件夹就相当于路由集合,比如说,首页是index.js,而如果url地址变成:3000/jspang.js那么其就会进入jspang.js文件。如果是多层的,那么路径就会变成:3000/blog/nextBlog.js

image-20220908211051641

1.导航式跳转

  1. 新建两个页面
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
// 这是A页面
import Link from 'next/link'
export default () => (
<>
<div>jspang - A页面</div>
<Link href='/'>
<a>返回首页</a>
</Link>
</>
)

//--------------------------------------------

// 这是B页面
import Link from 'next/link'
export default () => (
<>
<div>jspang - B页面</div>
<Link href='/'>
<a>返回首页</a>
</Link>
</>
)
  1. 编写首页
1
2
3
4
5
6
7
8
9
10
11
import React from 'react'
import Link from 'next/link'

const Home = () =>(
<>
<div>我是首页</div>
<div><Link href='/jspangA'><a>去jspangA页面</a></Link></div>
<div><Link href='/jspangB'><a>去jspangB页面</a></Link></div>
</>
)
export default Home

注意点

  • Link标签中只能包含一个跟标签,不能有同级标签

2.编程式跳转

使用Router方法可以实现跳转页面

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
import React from 'react';
import Link from 'next/link';
import Router from 'next/router';

const Home = () =>{
// 编写跳转方法
function gotoA() {
Router.push('/jspangA')
}
return (
<>
<div>我是首页</div>
<div><Link href='/jspangA'><a>去jspangA页面</a></Link></div>
<div><Link href='/jspangB'><a>去jspangB页面</a></Link></div>
<div>
<button onClick={gotoA}>jspangA</button>
</div>
</>
)
}
export default Home

3.传参

路由式传参

query传参

将参数放在url进行传递

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
import React from 'react'
import Link from 'next/link'

// query传递参数 老版本next.js仅仅支持query传参
const Home = () =>{

return (
<>
<div>我是首页</div>
<div>
<Link href="/chuancan?name=张三">
<a>跳转</a>
</Link>
// 第二种写法👇👇👇
<Link href={{pathname:'/chuancan',query:{name:'李四'}}}>
<a>李四</a>
</Link>
</div>
</>
)

}
export default Home



//-----接收参数-----

import React from 'react'
import {withRouter} from 'next/router';// 需要使用 withRouter 进行加工
import Link from 'next/link'

const Chuancan = ({router})=>{
return (
<>
<div>{router.query.name}</div>
<Link href='/'><a>返回首页</a></Link>
</>
)
}

export default withRouter(Chuancan)

编程式传参

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
import React from 'react'
import Link from 'next/link'
import Router from 'next/router'

// query传递参数 老版本next.js仅仅支持query传参
const Home = () =>{

function goto(){
Router.push({
pathname:'/chuancan',
query:{
name:'张三'
}
})
}
return (
<>
<div>我是首页</div>
<div>
<Link href="/chuancan?name=张三">
<a>跳转</a>
</Link>
</div>
<div>
<button onClick={goto}>点击跳转并携带参数</button>
</div>
</>
)

}
export default Home

Next中的组件

在components文件下创建jspang.js组件

1
2
3
4
5
6
7
8
export default ({children})=> {
return (
<button>
{children}
</button>
)
}
//写一个简单的组件示例

在首页文件中导入

1
2
3
4
5
6
7
8
import Jspang from '../components/jspang' // 引入按钮组件
export default function Home() {
return (
<div>
<Jspang>测试按钮组件</Jspang>
</div>
)
}

路由钩子事件

  • routeChangeStart 路由发生变化之前
  • routeChangeComplete 路由发生变化之后
  • beforeHistoryChange Next.js全部都用History模式
  • routeChangeError 路由发生错误时,404不算
  • hashChangeStart Hash路由切换之前
  • hashChangeComplete Hash路由切换完成
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
import React from 'react'
import Link from 'next/link'
import Router from 'next/router'

const Home = () =>{
// routeChangeStart 路由发生变化之前
// routeChangeComplete 路由发生变化之后
// beforeHistoryChange Next.js全部都用History模式
// routeChangeError 路由发生错误时,404不算
// hashChangeStart Hash路由切换之前
// hashChangeComplete Hash路由切换完成

Router.events.on('routeChangeStart',(...argus)=>{
// ...argus 返回路径和{shallow: false}对象
console.log('1.routeChangeStart,路由开始变化,参数为:',...argus);
})
Router.events.on('routeChangeComplete',(...argus)=>{
// ...argus 返回路径和{shallow: false}对象
console.log('2.routeChangeComplete,路由变化结束,参数为:',...argus);
})
Router.events.on('beforeHistoryChange',(...argus)=>{
// ...argus 返回路径和{shallow: false}对象
console.log('3.beforeHistoryChange,参数为:',...argus);
})
Router.events.on('routeChangeError',(...argus)=>{
// ...argus 返回路径和{shallow: false}对象
console.log('4.routeChangeError,路由发生错误时,参数为:',...argus);
})
Router.events.on('hashChangeStart',(...argus)=>{
// ...argus 返回路径和{shallow: false}对象
console.log('5.hashChangeStart,Hash路由切换之前,参数为:',...argus);
})
Router.events.on('hashChangeComplete',(...argus)=>{
// ...argus 返回路径和{shallow: false}对象
console.log('6.hashChangeComplete,Hash路由切换完成,参数为:',...argus);
})
function goto(){
Router.push({
pathname:'/chuancan',
query:{
name:'张三'
}
})
}

return (
<>
<div>我是首页</div>
<div>
<Link href="/chuancan?name=张三">
<a>张三</a>
</Link>
<Link href={{pathname:'/chuancan',query:{name:'李四'}}}>
<a>李四</a>
</Link>
</div>
<div>
<button onClick={goto}>点击跳转并携带参数</button>
</div>
</>
)

}
export default Home

Next.js中使用Axios

getiInitialProps是 Next.js 最伟大的发明,它确定了一个规范,一个页面组件只要把访问 API 外部资源的代码放在 getInitialProps 中就足够,其余的不用管,Next.js 自然会在服务器端或者浏览器端调用getInitialProps来获取外部资源,并把外部资源以 props 的方式传递给页面组件。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
import React from 'react'
import {withRouter} from 'next/router';
import Link from 'next/link'
import axios from 'axios';

const Chuancan = ({router,data})=>{ // 仅仅在withRouter下使用
return (
<>
<div>{router.query.name}</div>
<div>
{
data.map(ele=>{
return <p key={ele.title}>{ele.title}</p>
})
}
</div>
<Link href='/'><a>返回首页</a></Link>
</>
)
}

Chuancan.getInitialProps = async ()=>{
const promise = new Promise((resolve)=>{
axios('http://192.168.210.146:9527/api/goodList?page=1').then((res)=>{
console.log('数据:',res);
resolve(res)
})
})
return await promise
}
export default withRouter(Chuancan)

使用Style jsx编写页面

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
import React,{useState} from 'react';

function Jspang() {
const [color,setColor] = useState();

const changeColor=()=>{
setColor(color==='blue'?'red':'blue')
}

return (
<>
<div>测试文本</div>
<div><button onClick={changeColor}>改变颜色</button></div>

<style jsx>
{`
div{color:${color};}
`}
</style>
</>
)
}
export default Jspang

LazyLoading懒加载

外部库实现方式

采用异步引入的方式,仅在需要的时候引入使用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
import React,{useState} from 'react';

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>
<div><button onClick={changeTime}>改变时间格式</button></div>
</>
)
}

export default Time

自定义库

自定义一个组件

1
export default ()=><div>Lazy Loading ...</div>

引入next的dynamic

仅在使用的时候生效

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
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

自定义Head

为优化SEO,请求头是必不可少的,自定义请求头可以是SEO更加便捷找到页面

为方便可以将头做成组件,当然也可以每个页面使用不同的Head

使用Next提供的组件<Head/>

1
2
3
4
5
6
7
8
9
10
11
import Head from 'next/head'
const MyHeader = ()=>{
return (
<>
<Head>
<title>JSPang.com</title>
</Head>
</>
)
}
export default MyHeader

在需要的时候引入

1
2
3
4
5
6
7
8
9
10
11
import MyHeader from "../components/myHeader"

export default function Header() {
return (
<>
<MyHeader/>
<div>Header</div>
</>
)
}

Next.js中使用css

Next中是无法正常引入css进行使用的,参考官方文档

  1. 在pages文件下新建_app.js
  2. 新建style.css全局样式文件
1
2
3
4
5
6
7
// _app.js

import './styles.css'; //你的全局css样式

export default function MyApp({Component,pageProps}){
return <Component {...pageProps}></Component>
}
  1. 如果是组件的话可以在组件内引入
1
2
3
4
5
6
7
8
9
10
import 'antd/dist/antd.css'
import {Button} from 'antd'

export default function Header() {
return (
<>
<Button>按钮</Button>
</>
)
}