概述

该项目还有些功能在开发过程中,如果您有什么需求,欢迎您与我联系。我希望能够通过这个项目对React初学者,或者Babel/webpack初学者都有一定的帮助。我在此再强调一下,在我写的这些文章末尾都附加了很多参考文献,而这些参考文献的作用对我的帮助真的很大,在此表示感谢!!!!!

详细

写在前面的话

自已以前对redux,React,rect-redux,react-router都是有一点的了解,并且在真实的项目中也多少有些涉及。但是不足的地方在于没有做一个demo将他们串起来,所以总是感觉似懂非懂。特别是react服务端渲染这一块,对于自己完全就是一个黑箱,这对我深入理解react同构等稍微难一点的内容产生了很大的影响。所以我最后写了这个例子,希望有同样困扰的同学能够有所收获。也欢迎star,issue。

不得不说,当你真实的去做一个项目的时候,哪怕是一个小小的demo,这都会完全颠覆你对React生态的认识。从一开始的不知道如何入手,到遇到各种困难,然后各种google,最后解决问题,你会发现自己是真的在成长。遇到的问题以及解决方案,我在文章列表中也给出了。时间+经历=成长,对于我来说就够了。默默的对自己说一句,加油把少年!

1、项目说明

首先下载该项目,然后直接运行下面的命令。

  1. npm install
  2. npm run dev
  3. //npm run pro
  4. //生产模式下执行注释部分命令

打开http://localhost:3222/ 就可以看到效果。项目截图如下:

2、项目基本知识点

2.1 代理与反代理的基本内容

使用http-proxy来完成。其反向代理的原理如下图:

通过如下代码完成,其相当于一个反向代理服务器,向我们的代理服务器,即API服务器发送请求:

  1. const targetUrl = 'http://' + (process.env.APIHOST||"localhost") + ':' + (process.env.APIPORT||"8888");//其中APIHOST和APIPORT分别表示API服务器运行的域名与端口号const proxy = httpProxy.createProxyServer({
  2. target:targetUrl,
  3. ws:true
  4. //反代理服务器与服务器之间支持webpack socket});
  5. app.use("/api",(req,res)=>{
  6. proxy.web(req,res,{target:targetUrl});
  7. });
  8. app.use('/ws', (req, res) => {
  9. proxy.web(req, res, {target: targetUrl + '/ws'});
  10. });

2.2 react全家桶常见库

react-router,react,redux,react-redux,redux-async-connect,redux-thunk等一系列react相关的基本内容。其中最重要的就是我们的redux-async-connect,他可以在跳转到某个页面之前或者之后发起某一个ajax请求。用法如下:

  1. @asyncConnect([{ //其中helpers来自于服务端渲染
  2. promise: ({store: {dispatch, getState},helpers}) => { const promises = []; const state = getState(); //得到store的当前状态
  3. if(!isInfoLoaded(state)){
  4. promises.push(dispatch(loadInfo()));
  5. } if(!isAuthLoaded(state)){
  6. promises.push(dispatch(loadAuth()));
  7. } //如果没有登录或者相应的数据没有加载完成,那么我们在此时加载数据
  8. return Promise.all(promises);
  9. }
  10. }])

其中helpers方法来自于其服务端渲染的loadOnServer方法:

  1. loadOnServer({...renderProps, store, helpers: {client}}).then(() => { const component = ( <Provider store={store} key="provider">
  2. <ReduxAsyncConnect {...renderProps} />
  3. <\/Provider>
  4. )
  5. res.status(200);
  6. global.navigator = {userAgent: req.headers['user-agent']};
  7. res.send('<!doctype html>\n' +
  8. renderToString(<Html assets={webpackIsomorphicTools.assets()} component={component} store={store}\/>));
  9. });

2.3 自定义bootstrap

使用bootstrap-loader来加载自定义的bootstrap文件(.bootstraprc),从而减小打包后文件的大小。我们通过在项目目录下建立.bootstraprc文件,该文件可以指定我们需要使用的bootstrap样式,是否使用JavaScript等。如通过下面的配置:

  1. scripts: false

就可以在当前应用中不引入bootstrap的javascript,而只是单独使用样式。如果在单独使用样式的情况下我们可以结合react-bootstrap,react-router-bootstrap来完成页面的各种交互。如果你要单独使用这部分的内容,你可以参考这里

2.4 webpack的HMR功能集成

使用webpack实现HMR(react-transform-hmr)等基本功能,以及介绍了webpack-dev-middleware,webpack-hot-middleware等的使用。

  1. babelReactTransformPlugin[1].transforms.push({
  2. transform: 'react-transform-hmr',
  3. imports: ['react'],
  4. locals: ['module']
  5. });

如果你想深入了解HMR,你也可以参考这里

2.5 redux开发工具使用

redux-devtools,redux-devtools-dock-monitor,redux-devtools-log-monitor等redux开发工具的使用。只需要添加下面的一段代码就可以了:

  1. import React from 'react';
  2. import { createDevTools } from 'redux-devtools';
  3. import SliderMonitor from "redux-slider-monitor";
  4. import LogMonitor from 'redux-devtools-log-monitor';
  5. import DockMonitor from 'redux-devtools-dock-monitor';
  6. export default createDevTools( <DockMonitor changeMonitorKey='ctrl-m' defaultPosition="right" toggleVisibilityKey="ctrl-H"
  7. changePositionKey="ctrl-Q">
  8. <LogMonitor />
  9. <SliderMonitor keyboardEnabled />
  10. <\/DockMonitor>);

当然,如果要添加这部分代码要做一个判断:

  1. if (__DEVELOPMENT__ && __CLIENT__ && __DEVTOOLS__) { const { persistState } = require('redux-devtools'); const DevTools = require('../containers/DevTools/DevTools');
  2. finalCreateStore = compose(
  3. applyMiddleware(...middleware),
  4. window.devToolsExtension ? window.devToolsExtension() : DevTools.instrument(), //如果有window.devToolsExtension,那么使用用户自己的,否则使用我们配置的
  5. persistState(window.location.href.match(/[?&]debug_session=([^&]+)\b/))
  6. )(_createStore);
  7. }

也就是说我们只会在开发模式下,同时客户端代码(服务端显然是不需要的,该工具只是为了在客户端查看当前state的状态)中,以及DEVTOOLS为true中才会添加我们的devTool工具。

2.6 react服务器端同构

服务端同构是react开发中不可避免的问题,因为服务端渲染在一定程度上能够减少首页白屏的时间,同时对于SEO也具有很重要的作用。React中关于服务端渲染的介绍只是给出一个match方法,而更加深入的知识却要自己反复琢磨。

  1. match({ history, routes: getRoutes(store), location: req.originalUrl }, (error, redirectLocation, renderProps) => { if (redirectLocation) {
  2. res.redirect(redirectLocation.pathname + redirectLocation.search); //重定向要添加pathname+search
  3. } else if (error) {
  4. console.error('ROUTER ERROR:', pretty.render(error));
  5. res.status(500);
  6. hydrateOnClient();
  7. } else if (renderProps) {
  8. loadOnServer({...renderProps, store, helpers: {client}}).then(() => { const component = ( <Provider store={store} key="provider">
  9. <ReduxAsyncConnect {...renderProps} />
  10. <\/Provider>
  11. );
  12. res.status(200);
  13. global.navigator = {userAgent: req.headers['user-agent']};
  14. res.send('<!doctype html>\n' +
  15. renderToString(<Html assets={webpackIsomorphicTools.assets()} component={component} store={store}\/>));
  16. });
  17. } else {
  18. res.status(404).send('Not found');
  19. }
  20. });
  21. });

针对这部分内容我写了react服务端渲染中的renderProps与react-data-checksum以及React服务端同构深入理解与常见问题等系列文章,也欢迎阅读。文中提到了webpack-isomorphic-tools,该工具使得在服务端也能够处理less/css/scss,image等各种文件,从而使得服务端同构成为现实(服务端可以使用css module等特性生成className,从而使得checksum在客户端与服务端一致,防止客户端重新渲染)。

2.7 各种打包工具

better-npm-run以及webpackcc等打包工具的使用。前者在package.json中直接配置就行:

  1. "betterScripts": {
  2. "start-prod": {
  3. "command": "node ./bin/server.js",
  4. "env": {
  5. "NODE_PATH": "./src",
  6. "NODE_ENV": "production",
  7. "PORT": 8080,
  8. "APIPORT": 3030
  9. }
  10. }
  11. }

其主要作用在于方便设置各种环境变量。而webpackcc集成了多种打包方案,总有一个适合你

2.8 服务端客户端其他的库

superagent,express等与服务器相关的内容。其中前者主要用于向服务端发送请求,包括服务端向反向代理服务器以及客户端向服务器发送请求。

  1. const methods = ['get', 'post', 'put', 'patch', 'del'];
  2. import superagent from 'superagent'; this[method] = (path, { params, data } = {}) => new Promise((resolve, reject) => { const request = superagent[method](formatUrl(path)); if (params) {
  3. request.query(params);
  4. } //如果传入了参数,那么通过query添加进去
  5. if (__SERVER__ && req.get('cookie')) {
  6. request.set('cookie', req.get('cookie'));
  7. } if (data) {
  8. request.send(data);
  9. } //request.end才会真正发送请求出去
  10. request.end((err, { body } = {}) => err ? reject(body || err) : resolve(body));
  11. }));

2.9 高阶组件的组件复用逻辑

高阶组件对于组件复用是相当重要的。比如有一种情况,你需要获取所有的用户列表,图书列表,**列表等等,然后在数据获取完成后来重新渲染组件,此时你也可以考虑高阶组件的方式:

  1. //此时我们只是需要考虑真正的异步请求数据的逻辑,以及对prop进行特别处理的逻辑,而不用管当前是图书列表,还是用户列表等等function connectPromise({promiseLoader, mapResultToProps}) {
  2. return Comp=> { return class AsyncComponent extends Component {
  3. constructor(props) {
  4. super(); this.state = {
  5. result: undefined
  6. }
  7. }
  8. componentDidMount() {
  9. promiseLoader()
  10. .then(result=> this.setState({result}))
  11. }
  12. render() { return ( <Comp {...mapResultToProps(props)} {...this.props}/>
  13. )
  14. }
  15. }
  16. }
  17. }
  18. const UserList = connectPromise({
  19. promiseLoader: loadUsers,
  20. mapResultToProps: result=> ({list: result.userList})
  21. })(List); //List can be a pure component
  22.  
  23. const BookList = connectPromise({
  24. promiseLoader: loadBooks,
  25. mapResultToProps: result=> ({list: result.bookList})
  26. })(List);

你应该很容易就看出来了,对于这种列表类型的高阶组件抽象是相当成功的。我们只需要关注重要的代码逻辑,在componentDidMount请求数据结束后我们会自动调用setState来完成组件状态的更新,而真实的更新的组件却是我们通过自己的业务逻辑来指定的,可以是BookList,UserList,**List等等。这样具有副作用的高阶组件复用也就完成了。如果你需要深入了解高阶组件的内容,请查看我的这篇文章。在该项目中我们使用了multireducer

3、React全家桶文章总结

关于该项目中使用到的所有的react相关知识点我都进行了详细总结。但是很显然,如果你要学习react,必须对webpack和babel都进行一定的了解。因为在写这个项目之前,我只是一个react/webpack/babel的新手,因此也是在不断的学习中摸索前进的。遇到了问题就各种google,baidu。而且我对于自己有一个严格的要求,那就是要知其然而且要知其所以然,因此我会把遇到的问题都进行深入的分析。下面我把我在写这个项目过程遇到问题,并作出的总结文章贴出来,希望对您有帮助。我也希望您能够关注每一篇文章下面的参考文献,因为他们确实都是非常好的参考资料。

3.1 React+redux相关

React高阶组件详解

React同构你了解多少以及常用问题

renderProps签名与React服务端渲染

React的material-ui学习实例

react的context困境与解决方法

redux-form的使用实例

redux的原理浅析

使用react组件的ref回调函数

react-redux服务端渲染的一个完整例子

3.2 webpack相关

webpack-dev-server原理分析

webpack热加载HMR深入学习

集成webpack,webpack-dev-server的打包工具

prepack与webpack对比

webpack插件书写你需要了解的知识点

CommonsChunkPlugin深入分析

CommonsChunkPlugin配置项深入分析

webpack.DllPlugin提升打包性能

webpack实现code splitting方式分析

webpack中的externals vs libraryTarget vs library

webpack的compiler与compilation对象

webpack-dev-middleware原理分析

3.3 Babel相关

Babel编译class继承与源码打包结果分析

使用babel操作AST来完成某种特效

babylon你了解多少

3.4 其他内容

bootstrap-loader自定义bootstrap样式

前端工程师那些shell命令学习

npm环境变量与常见命令

npm中script生命周期方法的深入探讨

npm version与npm dist tag详解

linux中软链接与硬链接的区别学习

React路上遇到的那些问题以及解决方案

npm,webpack学习中遇到的各种问题

4、你能够学到的东西

内部所有的代码都有详细的注释,而且都给出了代码相关说明的链接。通过这个项目,对于react*全家桶*应该会有一个深入的了解。该项目牵涉到了常见的React生态中的库,因此命名为全家桶。该项目用到的React生态的主要库如下:

  1. react react-addons-perf react-bootstrap react-dom react-helmet react-redux react-router react-router-bootstrap react-router-redux react-tap-event-plugin react-transform-hmr redux redux-async-connect redux-devtools redux-devtools-dock-monitor redux-devtools-log-monitor redux-form, redux-slider-monitor redux-thunk multireducer ........

注:本文著作权归作者,由demo大师发表,拒绝转载,转载需要作者授权

初学者的React全家桶完整实例的更多相关文章

  1. react全家桶从0搭建一个完整的react项目(react-router4、redux、redux-saga)

    react全家桶从0到1(最新) 本文从零开始,逐步讲解如何用react全家桶搭建一个完整的react项目.文中针对react.webpack.babel.react-route.redux.redu ...

  2. 使用react全家桶制作博客后台管理系统 网站PWA升级 移动端常见问题处理 循序渐进学.Net Core Web Api开发系列【4】:前端访问WebApi [Abp 源码分析]四、模块配置 [Abp 源码分析]三、依赖注入

    使用react全家桶制作博客后台管理系统   前面的话 笔者在做一个完整的博客上线项目,包括前台.后台.后端接口和服务器配置.本文将详细介绍使用react全家桶制作的博客后台管理系统 概述 该项目是基 ...

  3. 基于react全家桶+antd-design+webpack2+node+express+mongodb开发的前后台博客系统

    很久没更新博客,最近也有点忙,然后业余时间搞了一个比较完整基于react全家桶+antd-design+webpack2+node+express+mongodb开发的前后台博客系统的流程系统,希望对 ...

  4. 使用react全家桶制作博客后台管理系统

    前面的话 笔者在做一个完整的博客上线项目,包括前台.后台.后端接口和服务器配置.本文将详细介绍使用react全家桶制作的博客后台管理系统 概述 该项目是基于react全家桶(React.React-r ...

  5. React全家桶+Material-ui构建的后台管理系统

    一.简介 一个使用React全家桶(react-router-dom,redux,redux-actions,redux-saga,reselect)+Material-ui构建的后来管理中心. 二. ...

  6. 使用React全家桶搭建一个后台管理系统

    引子 学生时代为了掌握某个知识点会不断地做习题,做总结,步入岗位之后何尝不是一样呢?做业务就如同做习题,如果‘课后’适当地进行总结,必然更快地提升自己的水平. 由于公司采用的react+node的技术 ...

  7. react-music React全家桶项目,精品之作!

    React-Music 全家桶项目,精品之作! 一.简介 该项目是基于React全家桶开发的一个音乐播放器,技术栈采用:Webpack + React + React-redux + React-ro ...

  8. webpack4 中的最新 React全家桶实战使用配置指南!

    最新React全家桶实战使用配置指南 这篇文档 是吕小明老师结合以往的项目经验 加上自己本身对react webpack redux理解写下的总结文档,总共耗时一周总结下来的,希望能对读者能够有收获, ...

  9. vue全家桶和react全家桶

    vue全家桶:vue  +  vuex (状态管理)  + vue-router (路由) + vue-resource +axios +elementui react全家桶 : react + re ...

随机推荐

  1. iOS中安全结束 子线程 的方法

    一个典型的结束子线程的方法:   用 isFinished 检测子线程是否被完全kill掉 -(IBAction)btnBack:(id)sender { //释放内存 仅仅remove 并不会触发内 ...

  2. andriod 文本居中: android:gravity="center"

    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools=&q ...

  3. [Git] 技术的热门度曲线

    reference :http://www.ruanyifeng.com/blog/2017/03/gartner-hype-cycle.html reference : https://stateo ...

  4. C++类模板的声明和定义为什么要放在同一个文件

    不是只能放在.h里面,但是推荐放在.h里面.STL模板实现全部是放在.h里面的.------------------编译能通过.1)参与编译的只是.cpp文件,不会报错的原因,是因为它能在.h里面找到 ...

  5. 解析KML文件并提取coordinates中的经纬度坐标信息

    从googleEarh导出的kml文件 <?xml version="1.0" encoding="UTF-8"?><kml xmlns=&q ...

  6. iOS开发-plist文件增删改查

    plist第一次看到这个后缀名文件的时候感觉怪怪的,不过接触久了也就习以为常了,plist是Property List的简称可以理解成属性列表文件,主要用来存储串行化后的对象的文件.扩展名为.plis ...

  7. Android -- 保存文件

    背景                                                                                             我们以常见 ...

  8. C++学习笔记12-模板1

     1.  函数模板 函数模板是一个独立于类型的函数,可作为一种方式.产生函数的特定类型版本号. // implement strcmp-like generic compare function // ...

  9. C++:fread、fwrite函数用法

    主要内容: fread.fwrite函数的用法 1.函数功能 用来读写一个数据块. 2.一般调用形式 fread(buffer,size,count,fp); fwrite(buffer,size,c ...

  10. C#.NET常见问题(FAQ)-abstract抽象类如何理解

    例如有太多相似,但是不一样的类,他们都继承自同一个基类(比如大型游戏有各个种族,每个种族有各种人物,加起来几百种类型,然后基本上他们都是一个角色,都有基本相同的属性和方法,比如都会走,只是速度不同,都 ...