前面两篇关于webpack的基础和进阶,请先务必阅读之前的文章。

Webpack教程一

Webpack教程二

什么是React

React是一个由Facebook开发的library,它的口号是“A JAVASCRIPT LIBRARY FOR BUILDING USER INTERFACES”,用于构建用户界面的库。他的特点是仅仅关注于UI层,和其他的一系列大型的框架(Ember.js和Angular.js等)的理念不同,上述两个框架给你提供了一整套的解决方案。还有一个重大的改革就是React采用了一种独特的技术被称为virtual DOM ,和其他传统框架的DOM渲染过程不同,提供了更高性能的渲染,

如果你对virtual DOM感兴趣,可以看看这个库:Matt-Esch/virtual-dom

如果你想深入了解React 请前往官方网站React.js

为什么要用React和Webpack配合在一起

现在有很多的构建工具,采用Webpack的原因就是简单易用,容易上手,并且对React完美的支持,比如说JSX语法,使用babel-loader以后可以很完美的支持,支持Hot Loading Component,让你不用忍受页面刷来刷去的痛苦,还有就是配置简单,loaders的魔力是没人能够拒绝的。

如果你的下一个项目采用React做为View的展示框架,不妨再使用Webpack一起搭建一个开发环境。

配置React和Webpack

现在开始配置,把两个库的魔力融合在一起,在这里同样是实践出真知,来做一个小项目一步步完成这部教程,项目很简单,不是已经被别人做烂了的Todo了,这个项目可以搜索github上的用户名称,并且展示出来搜索出来的信息。 先画一个原型图:

从上图可以看出 项目有两个components,一个是搜索框,一个是展示列表,列表有几种状态,初始状态,正在读取数据,数据读取完毕展示列表。

根据原型图,项目应该有如下简单的结构

程序结构

  • app/

    • index.jsx(程序入口)
    • components/(组件文件夹)
      • plist.jsx(展示用户列表)
      • search.jsx(搜索框组件)
    • utils/(一些小工具)
  • package.json
  • webpack.config.js

配置Babel让React支持ES6

在前面的文章里面我们多次提到了Babel,对于React来说,Babel更是一个完美的伙伴。

同时React也做了更新,更好的支持了ES6的写法。

如果你现在还是用这种方法写你的component

var List = React.createClass({
getInitialState: function() {
return ['a', 'b', 'c']
},
render: function() {
return ( ... );
}
});
那么是时候采用ES6的写法了 React ES6 classes 这种写法看起来更棒,可读性也更强。一个直观的发现就是不用写getInitialState方法了,可以直接在constructor里面定义this.state的值,前端一直都是在高速前进的,采用最新的标准,使用最新的技术,这应该是每个人的追求,对吧。

import React from 'react';

class List extends React.Component {
constructor() {
super();
this.state = ['a', 'b', 'c'];
}
render() {
return (...);
}
}

安装babel-loader

为了让上述的写法变成现实。需要安装bable和babel的两个preset:

//install babel core
npm install babel-loader --save-dev
//install es6 support and react support
npm install babel-preset-es2015 babel-preset-react --save-dev

这里安装了babel的主体和两个babel的preset, 什么是preset呢,你可以把preset看成一个包,里面有各种各样一系列的插件。

  • babel-preset-es2015 es6语法包,有了这个,你的代码可以随意的使用es6的新特性啦,const,箭头操作符等信手拈来。
  • babel-preset-react react语法包,这个包,是专门作为react的优化,让你在代码中可以使用React ES6 classes的写法,同时直接支持JSX语法格式。 更多详情,请到Babel Plugins看一下这两个语法包都包括什么插件,每个插件都有什么特性。

配置webpack

像我们在前面做到一样,创建webpack.config.js

var path = require('path');
var webpack = require('webpack');
var HtmlwebpackPlugin = require('html-webpack-plugin'); var ROOT_PATH = path.resolve(__dirname);
var APP_PATH = path.resolve(ROOT_PATH, 'app');
var BUILD_PATH = path.resolve(ROOT_PATH, 'build'); module.exports= {
entry: {
app: path.resolve(APP_PATH, 'index.jsx')
},
output: {
path: BUILD_PATH,
filename: 'bundle.js'
},
//enable dev source map
devtool: 'eval-source-map',
//enable dev server
devServer: {
historyApiFallback: true,
hot: true,
inline: true,
progress: true
},
//babel重要的loader在这里
module: {
loaders: [
{
test: /\.jsx?$/,
loader: 'babel',
include: APP_PATH,
query: {
//添加两个presents 使用这两种presets处理js或者jsx文件
presets: ['es2015', 'react']
}
}
]
},
plugins: [
new HtmlwebpackPlugin({
title: 'My first react app'
})
]
}

这里还需要添加一个resolve的参数,把jsx这种扩展名添加进去,这样就可以在js中import加载jsx这种扩展名的脚本

  ...
resolve: {
extensions: ['', '.js', '.jsx']
},
...

npm中添加webpack启动命令

就像第一章里面介绍的,把命令添加到package.json里面。

package.json

  ...
"scripts": {
"dev": "webpack-dev-server --progress --profile --colors --hot",
"build": "webpack --progress --profile --colors",
"test": "karma start"
},
...

添加首页

安装React和React-Dom

npm install react react-dom --save

让样式好看点,添加一个Bootstrap 4

npm install bootstrap@4.0.0-alpha.2 --save-dev

为了处理scss 需要添加sass loader 第一节讲过 大家都没忘记吧?

npm install css-loader style-loader sass-loader node-sass --save-dev

在webpack.config.js中添加处理的loader

 ...
module: {
loaders: [
...
{
test: /\.scss$/,
loaders: ['style', 'css', 'sass']
}
...
]
},
...

index.jsx 使用es6的格式

import '../node_modules/bootstrap/scss/bootstrap.scss';
import React from 'react';
import ReactDOM from 'react-dom'; class App extends React.Component{
constructor() {
super();
}
render() {
//JSX here!
return (
<div className="container">
<section className="jumbotron">
<h3 className="jumbotron-heading">Search Github Users</h3>
</section>
</div>
)
}
}; const app = document.createElement('div');
document.body.appendChild(app);
ReactDOM.render(<App />, app);

再用webpack运行就可以看到结果了。

npm run dev

大标题出现了。伟大的Babel和Bootstrap都被正确使用了。

添加React Transform支持

更新上面所说的React Hot Loading已经过时了,开发者也宣布已经停止维护,现在有一个更强大的babel plugin: React Transform来代替他。

现在每次修改一个component的代码,页面都会重新刷新,这会造成一个很不爽的问题,程序会丢失状态,当然现在在简单的程序中这个完全无所谓,但是假如程序变得越来越复杂,想要返回这种状态你可能又要经历一系列的点击等操作,会耗费一些时间。

隆重推出Babel-plugin-react-transform 名字挺长, 看起来挺吓人,其实你就可以想象用这个东西可以实时的对你的React Component做各种处理,它是基于Babel Plugin。 废话不多说,花点时间感受一下它是怎么玩的。

先安装

npm install --save-dev babel-plugin-react-transform

这是个基本的架子,可以通过它完成各种transform,如果想实现Hot Module Replacement (说白了就是页面不刷新,直接替换修改的Component),再安装一个transform.

npm install --save-dev react-transform-hmr

依赖就安装完毕了。

如果我们还要再来一个在页面上直接显示catch到的错误的transform,(不想打开console看到底有啥错误,直接显示在页面上多好),简单!再安装一个transform:

npm install --save-dev react-transform-catch-errors redbox-react

依赖安装完毕,配置Babel,上面说到把Babel的配置都写在webpack.config.js中,这是一个不好的方法,因为随着Babel的config越来越多,那样会显得非常臃肿,把babel的配置分离出来。

在跟目录新建一个Babel的配置文件: .babelrc, 把原来的配置写进去。

{
"presets": ["react", "es2015"]
}

现在在webpack里面的config就可以简化了,把那些query参数都删掉,简单了很多:

...
module: {
loaders: [
{
test: /\.jsx?$/,
loader: 'babel',
include: APP_PATH
}]
},
...

要让新建的两个transform生效,只需再安装一个present。

npm install babel-preset-react-hmre --save-dev

安装完毕,将支持HMR和Catch Error的present添加到.babelrc

{
"presets": ["react", "es2015"],
//在开发的时候才启用HMR和Catch Error
"env": {
"development": {
"presets": ["react-hmre"]
}
}
}

配置完毕! 启动npm run dev

看看效果。然后随便改动h1标题里面的文字,发现页面没有刷新,但是自动内容自动改变了,在render方法中故意弄一些错误,出现了可爱的红色错误提示,大功告成~~~

继续项目

完美配置了Webpack和React的开发环境,现在让我们把小项目完成吧。

根据上面的图 把项目分为两个主要的component,一个是Search Box用来让用户填写用户名, 一个是List,用来展示搜索到用户的列表.

Search Box非常的简单 就是两个input,当用户点击Search的时候,把输入的名字发送到List的组件里面。

import React from 'react';
import ReactDOM from 'react-dom';
export default class Search extends React.Component {
constructor(props) {
super(props);
this.handleSearch = this.handleSearch.bind(this);
}
handleSearch() {
let name = ReactDOM.findDOMNode(this.refs.name).value;
if (name === '') {
return;
}
this.props.sendAction(name);
}
render() {
return (
<div>
<input type="text" ref="name" placeholder="enter the name you wanna search"/>
<button onClick={this.handleSearch}>Search</button>
</div>
)
}
}

List的目标是接受props传进来的name参数,发起一个ajax请求,然后用返回值更新整个列表,这个列表有几种状态 初始状态,第一次渲染返回一行提示文字。 Loading的状态,当有props传进来的时候,发起ajax请求,并且显示一个loading的提示。 完成状态,当请求完毕,渲染列表并且显示出来。

这个列表有不同的生命周期,这里简单介绍一下React Component的生命周期.

初始化的生命周期

如上图所描述的一样,当实例化一个Component的时候,会依次调用这些方法,所以在render完后做什么操作的话,可以把代码放到componentDidMount中。

当props属性发生变化以后的生命周期

如上图描述,当这个组件的props发送变化以后,会依次调用这些方法,当大体清楚了整个lifeCycle,是时候继续列表组件了。  

import React from 'react';
//自定义了一个ajax的方法,非常简单,支持promise
import {get} from '../utils/ajax'; export default class Plist extends React.Component { constructor(props) {
super(props);
this.state = {"loading":false, "list": []};
}
//当初次渲染完毕 设置该组件的属性firstView为true
componentDidMount() {
this.setState({"firstView": true});
}
//当传入的props有变化,请注意看上面第二张图,就是时候发起请求 更新列表的内容了
componentWillReceiveProps(nextProps) {
let keyword = nextProps.keyword;
//loading设为true,firstView设为false
this.setState({"loading": true, 'firstView': false});
let url = `https://api.github.com/search/users?q=${keyword}`;
//发起ajax请求
get(url).then((data) => {
//更新本组件的state
this.setState({"loading":false, "list": data.items});
}).catch((error) => {
console.error(error);
});
} render() {
const imgStyle = {
width: '50px'
}
//添加一些if else的判断,用来展示不同的内容
if (this.state.firstView) {
return (
<h2>Enter name to search</h2>
)
}
if (this.state.loading) {
return (
<h2>Loading result...</h2>
);
} else {
if (this.state.list.length === 0) {
return (
<h2>No result.</h2>
)
} else {
return (
<div className="row">
{this.state.list.map(people=>{
return (
<div className="card">
<img src={people.avatar_url} style={imgStyle}/>
<p className="card-text">
{people.login}
</p>
</div>
)
})}
</div>
);
}
}
}
}

最后把两个组件引用到App里面

import '../node_modules/bootstrap/scss/bootstrap.scss';
import React from 'react';
import Search from './components/search';
import Plist from './components/plist'; class App extends React.Component { constructor(props) {
super(props);
this.state = {"keyword": ""};
this.refreshKeyword = this.refreshKeyword.bind(this);
} refreshKeyword(name) {
this.setState({"keyword": name});
} render() {
return (
<div className="container">
<section className="jumbotron">
<h3 className="jumbotron-heading">Search Github Users</h3>
<Search sendAction={this.refreshKeyword}/>
</section> <Plist keyword={this.state.keyword}/>
</div>
);
}
}

  

大功告成!现在让webpack跑起来,看看成果。随便搜索一个关键词试一试:

没有搜索的初始化界面

搜索以后的结果

Webpack+React配合开发的更多相关文章

  1. Webpack+React+ES6开发模式入门指南

    React无疑是今年最火的前端框架,github上的star直逼30,000,基于React的React Native的star也直逼20,000.有了React,组件化似乎不再步履蹒跚,有了Reac ...

  2. webpack+react+es6开发模式

    一.前言 实习了两个月,把在公司用到的前端开发模式做个简单的整理.公司里前端开发模式webpack+react+redux+es6,这里去掉了redux. webpack, react, redux等 ...

  3. webpack+react+redux+es6开发模式

    一.预备知识 node, npm, react, redux, es6, webpack 二.学习资源 ECMAScript 6入门 React和Redux的连接react-redux Redux 入 ...

  4. webpack+react+redux+es6

    一.预备知识 node, npm, react, redux, es6, webpack 二.学习资源 ECMAScript 6入门 React和Redux的连接react-redux Redux 入 ...

  5. webpack学习(五)—webpack+react+es6(第1篇)

    如果你看过webpack学习系列的前一个文章,接下来做的东西会比较简单 :webpack学习(四)— webpack-dev-server react发展的很快,现在大部分开发react相关的项目,都 ...

  6. React配合Webpack实现代码分割与异步加载

    这是Webpack+React系列配置过程记录的第四篇.其他内容请参考: 第一篇:使用webpack.babel.react.antdesign配置单页面应用开发环境 第二篇:使用react-rout ...

  7. [webpack] 配置react+es6开发环境

    写在前面 每次开新项目都要重新安装需要的包,简单记录一下. 以下仅包含最简单的功能: 编译react 编译es6 打包src中入口文件index.js至dist webpack配置react+es6开 ...

  8. webpack+react+redux+es6开发模式---续

    一.前言 之前介绍了webpack+react+redux+es6开发模式 ,这个项目对于一个独立的功能节点来说是没有问题的.假如伴随着源源不断的需求,前段项目会涌现出更多的功能节点,需要独立部署运行 ...

  9. 使用 webpack + react + redux + es6 开发组件化前端项目

    因为最近在工作中尝试了 webpack.react.redux.es6 技术栈,所以总结出了一套 boilerplate,以便下次做项目时可以快速开始,并进行持续优化.对应的项目地址:webpack- ...

随机推荐

  1. ORA-00265: instance recovery required, cannot set ARCHIVELOG

    OS: Oracle Linux Server release 5.7 DB: Oracle Database 11g Enterprise Edition Release 11.2.0.3.0 - ...

  2. Android中焦点移到ListView的有关问题

    一个解决办法 这不是一个根本解决的方法:写一个新的class,继承ListView,覆盖onFocusChanged. @Override protected void onFocusChanged( ...

  3. linux之iptables总结

    netfilter/iptables概述:     netfilter/iptables是Linux内核防火墙架构,由netfilter实现功能,由iptables提供接口.     iptables ...

  4. Swift的一些基础内容

    //①判断字符串是否为空的方法 isEmpty var str:String = "www.baidu.com" if str.isEmpty { print("空字符串 ...

  5. ultraedit高亮显示设置

    ultraedit高亮显示设置 | 浏览:2333 | 更新:2014-02-20 23:05 1 2 3 4 5 6 7 分步阅读 百度经验:jingyan.baidu.com 写代码的人对ultr ...

  6. Android实现简单拨号器

    Android实现简单拨号器 开发工具:Andorid Studio 1.3 运行环境:Android 4.4 KitKat 代码实现 界面布局只有GridLayout和EditText两个控件,全部 ...

  7. 【转载】about slack

    About Slack slack is the difference b/w the REQUIRED TIME and the ARRIVAL TIME. 1.WHAT IS SLACK WITH ...

  8. 2.2孙鑫C++

    1.继承 动物有 吃 睡 呼吸的方法 当然 鱼也有    不用重复再定义 1)public 那里都可以访问 #include <iostream.h> class Animal //类 基 ...

  9. oracle11g创建数据库最后一步确定时弹出无法创建目录

    总的说是Windows7的权限问题 Windows7 dos命令下输入dbca创建数据库,因为权限问题,数据库将无法完成.所以还是在开始程序中打开dbca创建数据库比较好. Windows7 dos以 ...

  10. java web.xml配置详解(转)

    源出处:java web.xml配置详解 1.常规配置:每一个站的WEB-INF下都有一个web.xml的设定文件,它提供了我们站台的配置设定. web.xml定义: .站台的名称和说明 .针对环境参 ...