react看这篇就够了(react+webpack+redux+reactRouter+sass)
Posted 黄大渣渣
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了react看这篇就够了(react+webpack+redux+reactRouter+sass)相关的知识,希望对你有一定的参考价值。
本帖将对一下内容进行分享:
1、webpack环境搭建;
2、如何使用react-router;
3、引入sass预编译;
4、react 性能优化方案;
5、redux结合react使用;
6、fetch使用;
7、项目目录结构;
一、webpack配置,代码如下:
1、在根目录下新建一个webpack.config.js,这个为开发环境的webpack配置;因为得区分开发跟生产环境,所以还得新建一个webpack.production.config.js作为生产环境使用的配置文档,
webpack.config.js代码如下:
var path = require(\'path\') var webpack = require(\'webpack\') var htmlWebpackPlugin = require(\'html-webpack-plugin\'); var ExtractTextPlugin = require(\'extract-text-webpack-plugin\'); var OpenBrowserPlugin = require(\'open-browser-webpack-plugin\'); // var nodeModulesPath = path.resolve(__dirname, \'node_modules\') // console.log(process.env.NODE_ENV) module.exports = { entry: path.resolve(__dirname, \'app/index.jsx\'), output: { path: __dirname + "/build", filename: "bundle.js" }, resolve:{ extensions:[\'\', \'.js\',\'.jsx\'] }, module: { // preLoaders: [ // // 报错 ????? // {test: /\\.(js|jsx)$/, loader: "eslint-loader", exclude: /node_modules/} // ], loaders: [ { test: /\\.(js|jsx)$/, exclude: /node_modules/, loader: \'babel\' }, { test: /\\.scss$/, exclude: /node_modules/, loader: \'style!css!postcss!sass\' }, { test: /\\.css$/, exclude: /node_modules/, loader: \'style!css!postcss\' }, { test:/\\.(png|gif|jpg|jpeg|bmp)$/i, loader:\'url-loader?limit=10000\' }, // 限制大小10kb { test:/\\.(png|woff|woff2|svg|ttf|eot)($|\\?)/i, loader:\'url-loader?limit=10000\'} // 限制大小小于10k ] }, eslint: { configFile: \'.eslintrc\' // Rules for eslint }, postcss: [ require(\'autoprefixer\') //调用autoprefixer插件,例如 display: flex ], plugins: [ // html 模板插件 new HtmlWebpackPlugin({ template: __dirname + \'/app/index.tmpl.html\' }), // 热加载插件 new webpack.HotModuleReplacementPlugin(), // 打开浏览器 new OpenBrowserPlugin({ url: \'http://localhost:8888\' }), // 可在业务 js 代码中使用 __DEV__ 判断是否是dev模式(dev模式下可以提示错误、测试报告等, production模式不提示) new webpack.DefinePlugin({ __DEV__: JSON.stringify(JSON.parse((process.env.NODE_ENV == \'dev\') || \'false\')) }) ], devServer: { /*proxy: { // 凡是 `/api` 开头的 http 请求,都会被代理到 localhost:3000 上,由 koa 提供 mock 数据。 // koa 代码在 ./mock 目录中,启动命令为 npm run mock \'/api\': { target: \'http://localhost:3000\', secure: false } },*/ port: 8888, contentBase: "./public", //本地服务器所加载的页面所在的目录 colors: true, //终端中输出结果为彩色 historyApiFallback: true, //不跳转 inline: true, //实时刷新 hot: true // 使用热加载插件 HotModuleReplacementPlugin } }
webpack.production.config.js代码如下:
var path = require(\'path\') var webpack = require(\'webpack\'); var HtmlWebpackPlugin = require(\'html-webpack-plugin\'); var ExtractTextPlugin = require(\'extract-text-webpack-plugin\'); module.exports = { entry: { app: path.resolve(__dirname, \'app/index.jsx\'), // 将 第三方依赖 单独打包 vendor: [ \'react\', \'react-dom\', \'react-redux\', \'react-router\', \'redux\', \'es6-promise\', \'whatwg-fetch\', \'immutable\' ] }, output: { path: __dirname + "/build", filename: "[name].[chunkhash:8].js", publicPath: \'/\' }, resolve:{ extensions:[\'\', \'.js\',\'.jsx\'] }, module: { loaders: [ { test: /\\.(js|jsx)$/, exclude: /node_modules/, loader: \'babel\' }, { test: /\\.less$/, exclude: /node_modules/, loader: ExtractTextPlugin.extract(\'style\', \'css!postcss!less\') }, { test: /\\.css$/, exclude: /node_modules/, loader: ExtractTextPlugin.extract(\'style\', \'css!postcss\') }, { test:/\\.(png|gif|jpg|jpeg|bmp)$/i, loader:\'url-loader?limit=5000&name=img/[name].[chunkhash:8].[ext]\' }, { test:/\\.(png|woff|woff2|svg|ttf|eot)($|\\?)/i, loader:\'url-loader?limit=5000&name=fonts/[name].[chunkhash:8].[ext]\'} ] }, postcss: [ require(\'autoprefixer\') ], plugins: [ // webpack 内置的 banner-plugin new webpack.BannerPlugin("Copyright by wangfupeng1988@github.com."), // html 模板插件 new HtmlWebpackPlugin({ template: __dirname + \'/app/index.tmpl.html\' }), // 定义为生产环境,编译 React 时压缩到最小 new webpack.DefinePlugin({ \'process.env\':{ \'NODE_ENV\': JSON.stringify(process.env.NODE_ENV) } }), // 为组件分配ID,通过这个插件webpack可以分析和优先考虑使用最多的模块,并为它们分配最小的ID new webpack.optimize.OccurenceOrderPlugin(), new webpack.optimize.UglifyJsPlugin({ compress: { //supresses warnings, usually from module minification warnings: false } }), // 分离CSS和JS文件 new ExtractTextPlugin(\'[name].[chunkhash:8].css\'), // 提供公共代码 new webpack.optimize.CommonsChunkPlugin({ name: \'vendor\', filename: \'[name].[chunkhash:8].js\' }), // 可在业务 js 代码中使用 __DEV__ 判断是否是dev模式(dev模式下可以提示错误、测试报告等, production模式不提示) new webpack.DefinePlugin({ __DEV__: JSON.stringify(JSON.parse((process.env.NODE_ENV == \'dev\') || \'false\')) }) ] }
在开发环境中跑webpack.config.js,打包的时候跑webpack.production.config.js的代码
所有在package.json中分别设置命令:
在window系统下:
"scripts": { "test": "echo \\"Error: no test specified\\" && exit 1", "dev": "set NODE_ENV=dev && webpack-dev-server --progress --colors", "build": "rd/s/q build && NODE_ENV=production && webpack --config ./webpack.production.config.js --progress --colors" },
在Mac系统下:
"scripts": { "dev": "NODE_ENV=dev webpack-dev-server --progress --colors", "build": "rm -rf ./build && NODE_ENV=production webpack --config ./webpack.production.config.js --progress --colors" },
所有当运行npm run dev 的时候就跑开发环境的代码,当运行指令npm run build 的时候就会跑webpack.production.config.js进行打包。
关于webpack的详细配置这里就不再详细说明,有兴趣的可以去看下文档。
二、使用react-router
1、安装依赖:npm install react-router --save
2、在根目录下新建router文件夹,然后新建一个routerMap.jsx文件
3、routerMap.jsx代码如下
import React from \'react\' import { Router, Route, IndexRoute } from \'react-router\' import App from \'../containers/App\' import Home from \'../containers/HomePage/Home\' import List from \'../containers/ListPage/List\' import NotFound from \'../containers/NotFound/Notfound\' class RouteMap extends React.Component{ render(){ return( <Router history={this.props.history}> <Route path=\'/\' component={App}> <IndexRoute component={Home}/> <Route path=\'list\' component={List}/> <Route path="*" component={NotFound}/> </Route> </Router> ) } } export default RouteMap
4、在App.jsx里引用相应的路由切换组件{this.props.children}
import React from \'react\' import Head from \'../components/head/head\' import Menu from \'../components/Menu/menu\' class App extends React.Component { render() { return ( <div> <Head/> <div className="wrap"> <div className="menu"> <Menu/> </div> <div>{this.props.children}</div> </div> </div> ) } } export default App
5、在根目录下的入口文件index.jsx引入routerMap,
import React from \'react\'; import ReactDOM from \'react-dom\'; import RouteMap from \'./router/routerMap\' import {hashHistory} from \'react-router\' import \'./static/index.scss\' ReactDOM.render( <RouteMap history={hashHistory}/>, document.getElementById(\'root\') );
6、使用菜单链接进行路由跳转
import React from \'react\' import { Link } from \'react-router\' class Menu extends React.Component{ render(){ return( <div className="menu"> <ul> <li> <Link to="/">Home</Link> </li> <li> <Link to="/list" activeClassName="active">List</Link> </li> </ul> </div> ) } } export default Menu
react-router的使用基本就是这样,详细的参数配置可以具体看下文档
三、使用sass编译
如果想引入sass预编译处理,需要安装两个依赖,node-sass以及sass-loader,然后在webpack中配置相应的加载器
loaders: [ { test: /\\.scss$/, exclude: /node_modules/, loader: \'style!css!postcss!sass\' }, ]
这样就能编译sass了,可以加快编码速度。
四、react 性能优化方案
这里将介绍两种比较常用的性能优化方案
1、性能检测react-addons-perf
安装react 性能检测工具 npm install react-addons-perf --save,然后在./app/index.jsx中使用依赖:
// 性能测试 import Perf from \'react-addons-perf\' if (__DEV__) { window.Perf = Perf }
if(__DEV__)是指在Dev环境下使用这个性能检测,然后把他赋到widow对象下。
使用方法:
在操作程序之前先在控制台中输入Perf.start()开始监听,启动检测;然后操作程序,在进行若干操作之后输入Perf.stop()停止检测,然后再跑Perf.printWasted()然后打印出浪费性能的组件列表,如下图所示:
在开发中很有必要检测组件中的性能情况,如果是浪费几毫秒或者十几毫秒,感觉没有必要再去优化他,毕竟十几毫秒是很难感觉得出来的。当浪费时间比较多的话,比如几十毫秒以上,这就有必要值得去优化他了。
2、PureRenderMixin优化
React最基本的优化方案就是用PureRenderMixin,安装依赖:npm install react-addons-pure-render-mixin --save;
PureRenderMixin使用原理:
react有一个生命周期函数叫做shouldComponentUpdata,为此组件更新之前,这个函数都会返回true,默认情况下都是返回true,当返回false则组件不更新,所以,当组件的state或者props变化的时候应该返回true,但这两个值不变化的时候则返回false,所以我们不能一直让这个函数返回true,实际的开发中组件会受一些其他因素的影响当state或者props不变化的时候也更新,这是需要我们去阻止的,所以要重写shouldComponentUpdata这个函数,每次更新的时候判断props和state这两个属性,有变化则返回true,无变化则返回false;
使用方法:
import PureRenderMixin from \'react-addons-pure-render-mixin\' constructor(props, context) { super(props, context); this.shouldComponentUpdate = PureRenderMixin.shouldComponentUpdate.bind(this); this.state = { todos: [] } }
3、Immutable.js优化
Immutable.js主要是处理数据的,用的不多,这里不详细介绍
五、react-redux使用
redux使用分为5步:
1、定义计算规则,即reducers
在根目录下新建一个reducers的文件夹,里边新建一个index.js的文件用来放全部的规则文件,比如我需要定义userinfo部分的返回规则,则新建一个userinfo.js文件
然后在userinfo.js里边定义相应的规则:
这里通过 actionTypes来统一管理这些变量的名称,一是两个地方用到,二是为了统一管理,所以单独起的一个constants的文件,然后里边有一个userinfo.js的文件
userinfo代码如下:
然后reducers文件夹下index.js代码如下
reducers文件夹下index.js就是为了统一管理各个模块的数据,当有多个js时就可以把他们全部注册进combineReducers然后统一输出rootReducer。
2、生成store
在根目录下新建一个store文件夹,里边新建一个文件configureStore.js,代码如下:
import { createStore } from \'redux\' import rootReducer from \'../reducers\' //引入第一步生成的规则 export default function configureStore(initialState) { const store = createStore(rootReducer, initialState, // 触发 redux-devtools window.devToolsExtension ? window.devToolsExtension() : undefined ) return store }
3、引用store,监听变化
在根目录下入口文件index.jsx中引入store,然后用provide包裹着组件:
import React from \'react\' import { render } from \'react-dom\' import { Provider } from \'react-redux\' import configureStore from \'./store/configureStore\' import Hello from \'./containers/Hello\' const store = configureStore() render( <Provider store={store}> <Hello/> </Provider>, document.getElementById(\'root\') )
4、组件中把state值赋予到props,看hello.jsx的代码:
import React from \'react\' import { connect } from \'react-redux\' import { bindActionCreators } from \'redux\' import * as userinfoActions from \'../actions/userinfo\' import A from \'../components/A\' import B from \'../components/B\' import C from \'../components/C\' class Hello extends React.Component { render() { return ( <div> <p>hello world</p> <hr/> <A userinfo={this.props.userinfo}/> <hr/> <B userinfo={this.props.userinfo}/> <hr/> <C actions={this.props.userinfoActions}/> </div> ) } componentDidMount() { // 模拟登陆 this.props.userinfoActions.login({ userid: \'abc\', city: \'beijing\' }) } } //把state赋予到props->userinfo function mapStateToProps(state) { return { userinfo: state.userinfo } } //第五步:定义事件,触发action或者更改state的值,然后把事件赋予到props function mapDispatchToProps(dispatch) { return { userinfoActions: bindActionCreators(userinfoActions, dispatch) } } //通过connect函数把两个方法跟组件联系到一起然后输出 export default connect( mapStateToProps, mapDispatchToProps )(Hello)
5.如果想改变reduce里边state的值,那么就需要通过事件去dispatch action;
这里定义了一些action事件:
然后在组件中通过import * as userinfoActions from \'../actions/userinfo\'进来,接着通过函数
赋予到props userinfoActions 中;
接着就是使用:
componentDidMount() { // 模拟登陆 this.props.userinfoActions.login({ userid: \'abc\', city: \'beijing\' }) }
这里reduce的5步就总结完了,说的有点笼统,具体的方法建议还是先看下文档,这里将不进行细节方法介绍。
reduce代码已经方法GitHub上边:https://github.com/huangjia727461876/react-reduce.git,不明白的可以看下源码。
六、fetch使用
1、安装依赖
npm install whatwg-fetch --save
npm install es6-promise --save
在目录下起一个fetch的文件夹
然后建两个文件,一个get.js和post.js分别定义这两个方法
get.js代码如下:
import \'whatwg-fetch\' import \'es6-promise\' export function get(url) { var result = fetch(url, { credentials: \'include\', headers: { \'Accept\': \'application/json, text/plain, */*\' } }); return result; }
post.js代码如下:
import \'whatwg-fetch\' import \'es6-promise\' // 将对象拼接成 key1=val1&key2=val2&key3=val3 的字符串形式 function obj2params(obj) { var result = \'\'; var item; for (item in obj) { result += \'&\' + item + \'=\' + encodeURIComponent(obj[item]); } if (result) { result = result.slice(1); } return result; } // 发送 post 请求 export function post(url, paramsObj) { var result = fetch(url, { method: \'POST\', credentials: \'include\', headers: { \'Accept\': \'application/json, text/plain, */*\', \'Content-Type\': \'application/x-www-form-urlencoded\' }, body: obj2params(paramsObj) }); return result; }
用法:
import { get } from \'./get.js\' import { post } from \'./post.js\' export function getData() { // \'/api/1\' 获取字符串 var result = get(\'/api/1\') result.then(res => { return res.text() }).then(text => { console.log(text) }) // \'/api/2\' 获取json var result1 = get(\'/api/2\') result1.then(res => { return res.json() }).then(json => { console.log(json) }) } export function postData() { // \'/api/post\' 提交数据 var result = post(\'/api/post\', { a: 100, b: 200 }) result.then(res => { return res.json() }).then(json => { console.log(json) }) }
七、项目目录结构
以上是关于react看这篇就够了(react+webpack+redux+reactRouter+sass)的主要内容,如果未能解决你的问题,请参考以下文章