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)的更多相关文章
- Vue学习看这篇就够
Vue -渐进式JavaScript框架 介绍 vue 中文网 vue github Vue.js 是一套构建用户界面(UI)的渐进式JavaScript框架 库和框架的区别 我们所说的前端框架与库的 ...
- React入门看这篇就够了
摘要: 很多值得了解的细节. 原文:React入门看这篇就够了 作者:Random Fundebug经授权转载,版权归原作者所有. React 背景介绍 React 入门实例教程 React 起源于 ...
- [转]React入门看这篇就够了
摘要: 很多值得了解的细节. 原文:React入门看这篇就够了 作者:Random Fundebug经授权转载,版权归原作者所有. React 背景介绍 React 入门实例教程 React 起源于 ...
- ASP.NET Core WebApi使用Swagger生成api说明文档看这篇就够了
引言 在使用asp.net core 进行api开发完成后,书写api说明文档对于程序员来说想必是件很痛苦的事情吧,但文档又必须写,而且文档的格式如果没有具体要求的话,最终完成的文档则完全取决于开发者 ...
- .NET Core实战项目之CMS 第二章 入门篇-快速入门ASP.NET Core看这篇就够了
作者:依乐祝 原文链接:https://www.cnblogs.com/yilezhu/p/9985451.html 本来这篇只是想简单介绍下ASP.NET Core MVC项目的(毕竟要照顾到很多新 ...
- 想了解SAW,BAW,FBAR滤波器的原理?看这篇就够了!
想了解SAW,BAW,FBAR滤波器的原理?看这篇就够了! 很多通信系统发展到某种程度都会有小型化的趋势.一方面小型化可以让系统更加轻便和有效,另一方面,日益发展的IC**技术可以用更低的成本生产 ...
- [译]ASP.NET Core Web API 中使用Oracle数据库和Dapper看这篇就够了
[译]ASP.NET Core Web API 中使用Oracle数据库和Dapper看这篇就够了 本文首发自:博客园 文章地址: https://www.cnblogs.com/yilezhu/p/ ...
- ExpandoObject与DynamicObject的使用 RabbitMQ与.net core(一)安装 RabbitMQ与.net core(二)Producer与Exchange ASP.NET Core 2.1 : 十五.图解路由(2.1 or earler) .NET Core中的一个接口多种实现的依赖注入与动态选择看这篇就够了
ExpandoObject与DynamicObject的使用 using ImpromptuInterface; using System; using System.Dynamic; names ...
- 【转】ASP.NET Core WebApi使用Swagger生成api说明文档看这篇就够了
原文链接:https://www.cnblogs.com/yilezhu/p/9241261.html 引言 在使用asp.net core 进行api开发完成后,书写api说明文档对于程序员来说想必 ...
随机推荐
- php执行linux命令的6个函数
一般情况下,很少会用php去执行linux命令,不过特殊情况下,你也许会用到这些函数.以前我知道有二个函数可以执行linux命令,一个是exec,一个是shell_exec.其实有很多的,结合手册内容 ...
- Nginx负载均衡使用ip
upstream test1{ server 192.168.1.213; server 192.168.1.37; } server { listen 80; # default backlog=2 ...
- 高质量PHP代码的50个实用技巧必备(下)
26. 避免直接写SQL, 抽象之 不厌其烦的写了太多如下的语句: ? 1 2 <span style="color:#333333;font-family:''Helvetica, ...
- 轻谈BFC
BFC 定义 CSS2.1的定义 Block formatting contexts 9.4.1 Block formatting contexts Floats, absolutely positi ...
- Microsoft Visual Studio | VS打开解决方案时加载失败,或者出现错误提示
Microsoft Visual Studio | VS打开解决方案时加载失败,或者出现错误提示 1.加载失败并且输出状态栏也没什么错误提示的话,往往是因为一个低版本VS2010.VS2012等打开了 ...
- Python开发工具PyCharm个性化设置
Python开发工具PyCharm个性化设置,包括设置默认PyCharm解析器.设置缩进符为制表符.设置IDE皮肤主题等,大家参考使用吧 1.设置默认PyCharm解析器: 操作如下: Pyt ...
- WIN7下安装SVNserver端及client搭建协作环境
一.客户场景: 客户现场须要在虚拟机上封闭开发,所以须要搭建一个SVN协作开发环境.客户提供了一台全新的裸机安装的操作系统是WIN7旗舰版64位. 二.SVNserver搭建 1. SVNserver ...
- 卡尔曼滤波(Kalman Filter)
一.引言 以下我们引用文献[1]中的一段话作为本文的開始: 想象你在黄昏时分看着一仅仅小鸟飞行穿过浓密的丛林.你仅仅能隐隐约约.断断续续地瞥见小鸟运动的闪现.你试图努力地猜測小鸟在哪里以及下一时刻它会 ...
- Ubuntu下关闭防火墙
默认情况下ubuntu无firewall,除非你自己安装了,怎么装的就怎么删呗. . 假设是已启用的自备的iptables 删了即可了 sudo apt-get remove iptables.
- 入门Webpack
---恢复内容开始--- 什么是WebPack,为什么要使用它? 为什要使用WebPack 现今的很多网页其实可以看做是功能丰富的应用,它们拥有着复杂的JavaScript代码和一大堆依赖包.为了简化 ...