Next.js简介
Next.js 是一个轻量级的 React 服务端渲染应用框架。
完善的React项目架构,搭建轻松。比如:Webpack配置,服务器启动,路由配置,缓存能力,这些在它内部已经完善的为我们搭建完成了。
自带数据同步策略,解决服务端渲染最大难点。把服务端渲染好的数据,拿到客户端重用,这个在没有框架的时候,是非常复杂和困难的。有了Next.js,它为我们提供了非常好的解决方法,让我们轻松的就可以实现这些步骤。
丰富的插件帮开发人员增加各种功能。每个项目的需求都是不一样的,包罗万象。无所不有,它为我们提供了插件机制,让我们可以在使用的时候按需使用。你也可以自己写一个插件,让别人来使用。
灵活的配置,让开发变的更简单。它提供很多灵活的配置项,可以根据项目要求的不同快速灵活的进行配置。
目前Next.js是React服务端渲染的最佳解决方案,所以如果你想使用React来开发需要SEO的应用,基本上就要使用Next.js。
首先安装
yarn add react react-dom next
安装脚手架工具
npm install -g create-next-app
使用脚手架工具,通过npx方式创建
npm install -g npx
npx create-next-app next-test
全部安装完成后,可以进入项目母乳,执行yarn dev来测试项目,默认地址http://localhost:3000/。
配置忽略文件:
pages下面新建index.js文件,next会自动添加路由。如果添加多个页面,便可以通过<Link>跳转,引入便可以使用。
import Link from 'next/link'
export default ()=>(
<>
<Link href="/"><a>返回首页</a></Link>
</>
)
由于本项目为单页,并要配置到GitHub Pages,只建了一个页面,通过传统的react 组件方式调用。
首页jsx结构:
拆出Nav作为导航:
import Head from 'next/head'
import "../public/less/nav.less"
import React, { Component } from "react";
class Nav extends Component {
constructor(props) {
super(props);
}
render() {
const { value, onIncreaseClick } = this.props
return (
<>
<Head>
<title>马云模拟器</title>
<meta charSet='utf-8' />
</Head>
<div className="navclass">
<h3>余额:{value}</h3>
{/* <button type="button">购物车</button> */}
</div>
</>
)
}
}
export default Nav
next/head允许你在<Head></Head>标签中定义必要的信息,改变跳转后信息显示。
{value}为redux传入,下面会介绍。
列表主要拆出三个组件,用于数据的显示(其实一个就行,但是我只能传GitHub Pages上静态页面,所有数据都放一起很乱,所以就拆成了三个):
通过taplist控制组件显示。
新建并引入组件:
组件中import axios from 'axios'
componentWillMount(){
let _this = this;
const promise =new Promise((resolve)=>{
axios('../automobile/list.json').then(
(res)=>{
resolve(res.data)
}
)
})
promise.then(function(res){
let newarr = res.map(function(item){
return {...item,addnum: 0}
})
_this.setState({
list: newarr
})
})}
componentWillMount中请求后台数据,并setState到当前组件中(由于没有后台,本项目数据写死)数据结构如下:
this.setState({
list:[
{
"img":"images/zhengjiao.jpg",
"name":"蒸饺",
"number":"6",
"addnum": 0
},
{
"img":"images/huasheng.jpg",
"name":"花生米",
"number":"10",
"addnum": 0
},
{
"img":"images/zhacai.jpg",
"name":"榨菜",
"number":"12",
"addnum": 0
},
{
"img":"images/naicha.jpg",
"name":"奶茶",
"number":"25",
"addnum": 0
},
{
"img":"images/zhurou.jpg",
"name":"猪肉",
"number":"30",
"addnum": 0
},
{
"img":"images/fangtuo.jpg",
"name":"防脱洗发液",
"number":"70",
"addnum": 0
}
]
})
之后循环数据生成列表:
addlist(){
let arr;
if(this.state.list.length){
arr = this.state.list.map((item,i) =>{
return (<div className="auto_list" key={i}>
<img src={item.img}/>
<h3>{item.name}<span className="price">¥{item.number}</span></h3>
<div className="add_button">
<div className="control">
<div className="subtraction" onClick={()=>this.reducecar(i)}>
-
</div>
<div className="addnum">{item.addnum}</div>
<div className="addition" onClick={()=>this.addcar(i)}>
+
</div>
</div>
<button className="increase" onClick={()=>this.addcar(i)}>加入购物车</button>
</div>
</div>)
})
}
return arr;
}
render() {
return (
<>
<div>{this.addlist()}</div>
</>
);
}
点击购物车及加号执行addcar(i)并将点击的第几个传进去:
addcar(i){
let newaddnum = this.state.list[i].addnum+=1;
let newmoney = this.state.list[i].number;
let newprodata = this.state.value - (newaddnum*newmoney);
this.onIncreaseClick(newprodata);
let newlist = Object.assign([],this.state.list);
this.setState({
list:newlist
})
}
让当前列表下点击的产品个数+=1,Object.assign一个新数据,并setState到当前数据中。onIncreaseClick为redux方法,总钱数减去当前产品总钱数,然后执行此方法到父级中。
index中引入redux,做全局的数据管理:
import { createStore } from 'redux';
import { Provider,connect} from "react-redux";
//子组件传过来的值
let childrendata;
/*-----------具体通知描述及数据处理方法部分-------------*/
// Action通知及描述
const increaseAction = { type: 'reduce' }
// Reducer计算 基于原有state根据action得到新的state
function counter(state = { count: 279000000000}, action) {
const count = state.count;
switch (action.type) {
case 'reduce'://如果接到action为increase的通知执行
return { count: childrendata}
default:
return state//返回新的state
}
}
/*-----------数据存储器部分-------------*/
// 根据reducer函数通过createStore()创建store(存储器)
const store = createStore(counter)
/*-----------映射方法及数据部分-------------*/
// 将state映射到Counter组件的props(数据)
function mapStateToProps(state) {
return {
value: state.count
}
}
// 将action映射到Counter组件的props(方法)
function mapDispatchToProps(dispatch) {
return {
onIncreaseClick: function (data) {
childrendata = data;
dispatch(increaseAction)//定义点击方法发送action
}
}
}
// 传入上面两个函数参数,将Counter组件变为App组件
const App = connect(
mapStateToProps,
mapDispatchToProps
)(Counter)
const Home = () => {
return(
<Provider store={store}>
<App/>
</Provider>
)
}
export default Home
使用<Provider store={store}>将数据绑定到全局,便于子组件获取。connect()将映射方法传入,绑定到刚才生成的组件上,生成新的对象Home,并export default Home。onIncreaseClick方法触发dispatch(increaseAction)更新状态,并将子组件传过来的数据存为childrendata。
store方法counter中传两个值,state中count默认为279000000000,action为宣发室大爷。
switch (action.type) {
case 'reduce'://如果接到action为increase的通知执行
return { count: childrendata}
default:
return state//返回新的state
}
循环,如果为张大爷通知的,则返回子组件传过来的新数据。
项目预览地址:https://aotuotage.github.io/next-test/
代码地址:https://github.com/aotuotage/next-test
配置到github pages需要在根目录下,新建next.config.js,解析less等。
const withLess = require('@zeit/next-less');
const WithCss = require('@zeit/next-css');
// fix: prevents error when .less files are required by node
if (typeof require !== 'undefined') {
require.extensions['.less'] = file => {};
}
const prod = process.env.NODE_ENV === 'production';
module.exports = withLess(
WithCss({
lessLoaderOptions: {
modifyVars: {
'primary-color': '#1DA57A'
},
javascriptEnabled: true
},
// next-antd-ssr这个名字是你github项目名称
assetPrefix: prod ? '/next-test' : '',
publicRuntimeConfig: {
linkPrefix: prod ? '/next-test' : '',
staticFolder: '/public',
}
})
);
还需要配置bable,新建.babelrc。
{
"presets": ["next/babel"],
"plugins": [
// 可以使用装饰器decorator
["@babel/plugin-proposal-decorators", { "legacy": true }],
// 让我们可以使用根路径,避免相对路径的混乱,如import Head from '@/components/Head'
[
"module-resolver",
{
"alias": {
"@": "./"
}
}
],
// 按需加载并且可以使用less的配置
[
"import",
{
"libraryName": "antd",
"style": true
}
]
]
}
package.json中配置快捷命令:
"scripts": {
"dev": "next -p 3006",
"start": "next start -p 3006",
"build": "next build",
"export": "next build && next export && serve out",
"github": "rm -rf node_modules/.cache && next build && next export && touch out/.nojekyll && git add out/ && git commit -m \"Deploy Next.js to gh-pages\" && git subtree push --prefix out origin gh-pages"
}
执行yarn build之后再执行yarn github便可以将项目配置到github pages中了。