前言bb
前段时间,一同事问我react相关知识,我的大脑突然空白,许多细节都已模糊,回去看看以前的项目,才回想起来点,温故知新(捡起来)
- vue,react都是很好的框架,两则相互的竞争,相互借鉴,突破对方的弱点,相信前端会越来越好(近年来相对稳定,有好有坏吧,不管怎么说,不管什么行业,尤其靠技术吃饭的,自己不提升将会被时代抛弃)
同样服务端渲染的next框架
- nuxt搞过,好奇心:next也要学学,先学习该工具的使用
vue与react框架思想一样,那么相对应他们与之配套的服务端渲染nuxt和next是不是大同小异,gogogo
学习一个新语言,新框架,新工具,都请先阅读官方文档:Next英文文档,中文文档有点落后
一、搭建项目
官网脚手架 / 当然你也可以自己搭建,安装所需npm包即可
新版本next需要注意node版本10以上
npm init next-app
# or
yarn create next-app
使用官方cli初始化项目,就只一个pages文件夹,其他都需要你自己丰富
我的demo
目录结构
├── .next --------------------------- 打包后项目主文件
├── api ----------------------------- 说明文件
├── asyncData ------------------- node服务端请求接口
├── syncData -------------------- 浏览器请求接口
├── assets -------------------------- 项目静态资源文件目录(图片、公共样式、字体等)
├── components ---------------------- 组件
├── layouts ------------------------- 布局模式
├── pages --------------------------- 页面(该文件夹下也对应着项目路由路径)
├── server
└── index.js -------------------- node服务启动文件
├── static -------------------------- robot静态文件
├── store --------------------------- redux状态管理
├── utils --------------------------- 工具
├── next.config.js ------------------- webpack配置入口
├── package.json -------------------- 项目配置
老规矩,整理出页面所需要的基础配置与依赖
- webpack
- node服务配置
- 路由
- 获取数据和组件生命周期
- rudex状态管理
- 最后开始写页面或改造已有项目
基本目标确定,开始工作workwork
一、webpack
next并没有对该配置文件做多余的处理,编程者还是自己选择所需的打包吧
webpack使用zeit下提供的三连utils,简易的话就不用配置啦,相对nuxt,他就没有其他多余的配置,大多还是webpack的使用
next.config.js
const withSass = require('@zeit/next-sass')
const withCSS = require('@zeit/next-css')
const withSourceMaps = require('@zeit/next-source-maps')
module.exports = withSass(withCSS(withSourceMaps()))
二、node服务配置
server/index.js
这里可以使用express,也可以使用koa作为node框架服务
const express = require('express')
const next = require('next')
const compression = require('compression')
const dev = process.env.NODE_ENV !== 'production'
const app = next({dev})
const handle = app.getRequestHandler()
let port = dev ? 6666 : 8080
console.log('Waiting ready on http://localhost ' + port + ' ……')
// Pass in the absolute path to your robots.txt file
app.prepare()
.then(() => {
const server = express()
if (!dev) {
server.use(compression()) //gzip
}
// 动态请求处理,自定义路由映射
server.get('/a/:id', (req, res) => {
const actualPage = '/detail'
const queryParams = {id: req.params.id}
app.render(req, res, actualPage, queryParams)
})
server.get('/robots.txt', (req, res) => (
res.status(200).sendFile('robots.txt', optionsPlain)
));
server.get('/sitemap.html', (req, res) => (
res.status(200).sendFile('sitemap.html', optionsHtml)
));
server.get('/sitemap.xml', (req, res) => (
res.status(200).sendFile('sitemap.xml', optionsXml)
));
server.get('*', (req, res) => {
return handle(req, res)
})
server.listen(port, (err) => {
if (err) throw err
console.log('> Ready on http://localhost ' + port)
})
})
.catch((ex) => {
console.error(ex.stack)
process.exit(1)
})
- 其实对比nuxt,启动文件一样的,在该node入口服务文件中,使用express启动服务,对请求进行处理,再使用next模块render页面返回客户端。
- 这里还添加seo两大文件,robots.txt,sitemap.html,站点链接地图与访问指定可访问页面
三、路由
还是与nuxt一样,让我们不用关心与维护路由文件(app.js),那他的路由路径怎么对应,其实就是对应着pages下面的文件路径,即是页面路径。所以我们在写页面的时候,规范组件抽离至component文件夹,也不要有其他不是单独页面的文件
让我们看看他具体使用,两个页面如何跳转
- 一、link下必须是一个元素节点
- 二、想要页面跳转,link包裹的必须是a标签,其他标签href传递不下去,没用的哦,引用官方解释:The default behaviour for the <Link> component is to push a new url into the stack. You can use the replace prop to prevent adding a new entry.
// pages/index.js
import Link from 'next/link';
function Home() {
return (
<>
<ul>
<li>Home</li>
<li>
<Link href="/xiaojuzi">
<a>hello 小橘子</a>
</Link>
</li>
</ul>
<h1>首页</h1>
</>
);
}
export default Home;
// pages/xiaojuzi.js
import Link from 'next/link';
function About() {
return (
<>
<ul>
<li>
<Link href="/">
<a>首页</a>
</Link>
</li>
</ul>
</>
);
}
export default xiaojuzi;
如果很少访问某些页面,可以将其手动设置prefetch为false
<Link href="/xiaojuzi" prefetch={false}>
<a>666</a>
</Link>
我们关心的动态路由它又来了
- 方法一(服务端方式):动态路由映射,node服务配置文件中,我们对路由重新pushstate,当node服务接受到一个/a/1的请求,这个时候我们通过拦截,将路由映射到/detail的页面,并携带动态id参数过去,最后render页面
server.get('/a/:id', (req, res) => {
const actualPage = '/detail'
const queryParams = {id: req.params.id}
app.render(req, res, actualPage, queryParams)
})
- 方法二:next提供了特殊的文件命名,[id].js,在中括号就是动态的路由路径页面文件,该动态参数你可以在query中取到,来看官方例子与解释
Defining routes by using predefined paths is not always enough for complex applications, in Next.js you can add brackets to a page ([param]) to create a dynamic route (a.k.a. url slugs, pretty urls, et al).
Consider the following page pages/post/[pid].js:
import { useRouter } from 'next/router';
const Post = () => {
const router = useRouter();
const { pid } = router.query;
return <p>Post: {pid}</p>;
};
export default Post;
同理,多动态参数,那文件夹就使用[]来命名包裹
- 例:pages/post/[pid]/[comment].js将匹配/post/1/a-comment。它的query对象是:{ pid: '1', comment: 'a-comment' }。
四、获取数据和组件生命周期
与nuxt提供的asyncData一样,next也提供了钩子getInitialProps
- 在函数式组件中
import fetch from 'isomorphic-unfetch';
function Page({ stars }) {
return <div>Next stars: {stars}</div>;
}
Page.getInitialProps = async ({ req }) => {
const res = await fetch('https://api.github.com/repos/zeit/next.js');
const json = await res.json();
return { stars: json.stargazers_count };
};
export default Page;
- 在类组件中
import React from 'react';
class HelloUA extends React.Component {
static async getInitialProps({ req }) {
const userAgent = req ? req.headers['user-agent'] : navigator.userAgent;
return { userAgent };
}
render() {
return <div>Hello World {this.props.userAgent}</div>;
}
}
export default HelloUA;
getInitialProps 接收具有以下属性的上下文对象:
- pathname -URL的路径部分
- query -URL的查询字符串部分被解析为对象
- asPath- String实际路径(包括查询)的-在浏览器中显示
- req -HTTP请求对象(仅服务器)
- res -HTTP响应对象(仅服务器)
- err -渲染期间遇到任何错误的错误对象
五、rudex状态管理
依旧是快乐正常使用,在你的app最外层组件挂载,全局嘻嘻
看到一篇还可以的博客,还不会使用rudex的可以看看
六、默认页面
一、自定义app.js。Next.js使用该App组件来初始化页面。您可以覆盖它并控制页面初始化。这使您可以做一些令人惊奇的事情,例如:
- 页面更改之间的持久布局
- 导航页面时保持状态
- 使用自定义错误处理 componentDidCatch
- 将其他数据注入页面(例如,通过处理GraphQL查询)
要覆盖,请创建./pages/_app.js文件并覆盖App类
import React from 'react';
import App from 'next/app';
class MyApp extends App {
render() {
const { Component, pageProps } = this.props;
return <Component {...pageProps} />;
}
}
export default MyApp;
六、最后开始写页面或改造已有项目
enenen,细节部分还得多实践实践,最后奉上请求方案
axios.js
import axios from "axios";
import qs from "qs";
// 创建axios默认请求
axios.defaults.baseURL = "http://gongpengji.com";
// 配置超时时间
axios.defaults.timeout = 100000;
// 配置请求拦截
axios.interceptors.request.use(
// xxx
);
// 添加响应拦截器
axios.interceptors.response.use(
function(response) {
console.log(response);
return response;
},
function(error) {
// 对响应错误做点什么
return Promise.reject(error);
}
);
/**
* get请求
* @method get
* @param {url, params, loading} 请求地址,请求参数,是否需要加载层
*/
var get = function(url, params, loading) {
return new Promise((resolve, reject) => {
// {
// params: params
// }
axios
.get(url, params)
.then(res => {
resolve(res);
})
.catch(err => {
reject(err);
});
});
};
/**
* post请求
* @method post
* @param {url, params} 请求地址,请求参数,是否需要加载层
*/
var post = function(url, data) {
return new Promise((resolve, reject) => {
// qs.stringify(data)
axios
.post(url, data)
.then(res => {
console.log(res);
resolve(res);
})
.catch(err => {
reject(err);
});
});
};
export default { get, post };
思考
- 在看一边服务端渲染实现思想都是一样,两则使用上的不同,给我又一次不同的体会(英文文档真的难读,但看的越多越容易找到表达的关键点)【谷歌翻译随时点开哈哈哈】,发现在服务端进行请求路径修改并reader指定页面,确实nice。
- 现在清楚当客户端请求过来,nextjs才开始处理请求,并render,在这之间,我觉得还可以其他事件!
《盲女凶杀案》恐怖片高清在线免费观看:https://www.jgz518.com/xingkong/54000.html
《零异频道第二季》欧美剧高清在线免费观看:https://www.jgz518.com/xingkong/113884.html