使用react+redux搭建one单页应用
使用react+redux搭建one单页应用
2016-08-26

什么是React?

React

当今的前端正处于技术爆发期,这个阶段涌现很多优秀的编程思想以及框架,本文所介绍的react就是
前端的一种框架,它使用单向数据绑定以及jsx语法糖,通过它提供的特性,可以构建去区别于以前传统
型的网页。

什么是Redux?

redux

单页模式区别于传统模式开发,比如用户的登录状态、数据列表的缓存,传统类型的MVC设计模式中,后端语言(Java、PHP……)中,浏览器发起url请求,后端根据请求的路径和参数,后端对数据进行处理(从数据库中拿出数据、请求第三方接口等……),然后进行页面数据填充后返回完整的HTML数据,浏览器拿到这些html元素后进行页面渲染。

单页应用模式的区别在于请求进行接口化,开发过Android或者iOS的应该知道,客户端处理数据状态,操作UI控件,与后端进行网络通信获取数据通信。单页应用的开发就是基于这种模式,那么处理数据状态的任务就落到前端的头上来了,react提供视图渲染的优化,但是数据的状态管理就成了一个问题,比如用户的数据,交由那个组件去控制,怎么进行交互,这就成了一个问题。Facebook提出了Flux设计模型来解决这个问题,用store来存放数据源,通过action、reducer来操作数据,来保证数据的单一性。

但是Facebook只是提出了这一种设计思想,没有开发相应的框架,于是就诞生了很多第三方实现,Redux就是其中一种,它不是完全采用Flux规范模式,它提出了自己的设计思想,Redux也就成了和React搭配的优秀的状态工具。

项目生成

代码生成工具使用Yeoman,Yeoman是一个代码generators工具,它提供很多第三方generators,通过它,我们可以很方便的构建一个初始化项目,点击访问Yeoman

项目使用react+redux构建,所以这里选择generator-redux-stack来作为生成模板。终端下使用如下命令:

1
2
3
4
5
6
7
8
9
10
11
#安装yeoman
npm install yo -g

#安装generators
npm install -g generator-redux-stack

#创建目录并进入
mkdir [xxx] && cd [xxx]

#使用yo创建项目框架
yo redux-stack

执行完成后会看到下图
yo

填写相应的项目描述信息,Yeoman会自动创建文件,并且安装依赖

npm

如果网络较慢可以Ctrl+C停止安装,使用cnpm国内镜像安装(#滑稽)。

cnpm

稍等一会出现如下界面就说明完成了

finash

在终端输入

1
npm start

浏览器端打开http://localhost:3000可以看到生成器提供的模板

web

好了,接下来就可以开始编码了。:)

目录介绍

file

目录结构由redux-stack控制

目录名 描述
build 项目主html文件存放位置
dist 项目编译目录位置
node_modules npm包存放位置
server 项目运行时服务器环境
src 项目源码目录,代码主要存放位置
—-actions redux action存放目录
—-components react组件存放目录
—-config react-router主要配置文件
—-container react页面(组件拼贴)存放位置
—-reducers redux reducer存放位置
—-store redux store定义存放位置
—-style 样式文件存放位置
—-utils 开发调试工具配置
test 测试脚本存放目录

编写代码

编写jsx页面

container目录新创建一个Home.js文件

1
2
3
4
5
6
7
8
9
10
11
12
// src/containers/Home.js
import React, { Component } from 'react';

export default class Home extends Component {
render () {
return (
<div>
这是主页
</div>
)
}
}

这里创建了一个组件,组件渲染了一个div标签,里面是一行文字。render使用了jsx的语法糖。

编写路由

修改config目录下面的routes.js文件,需要引入Home组件,并且将其挂载到根节点。

1
2
3
4
5
6
// src/config/routes.js
import Home from '../containers/Home.js';

export default (
<Route path="/" component={Home} />
);

刷新路由器可以看到页面的更改

编写action

src/actioins目录下面创建one.js文件,这里面将会定义数据操作类型与一些actions方法。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// actions/one.js
import 'whatwg-fetch';
export const UPDATE_ONE = 'update_one';

export function update(_data) {
return {
type: UPDATE_ONE,
data: _data
};
}

export function getone() {
return dispatch => {
fetch('http://v3.wufazhuce.com:8000/api/hp/bymonth/2016-09')
.then((response) => {
console.log(response)
})
};
}

这里我们需要安装fetch来进行异步网络请求,当然你也可以使用其他网络请求工具。通过以下命令安装fetch

1
npm install whatwg-fetch --save

接口使用WeexOne项目里面的接口

编写reducer

redux-stack这个生成器自动帮我们做好了reducer到store的绑定,所以我们只需要将注意力放在reducer中就可以了。

src/reducers目录下新建one.js文件,这里我们将放置一些常用的数据操作。

1
2
3
4
5
6
7
8
9
10
11
// reducers/one.js
import { createReducer } from 'redux-create-reducer';
import { UPDATE_ONE } from '../actions/one';

const initialState = {};

export default createReducer(initialState, {
[UPDATE_ONE](state, data) {
return data.data;
}
});

并在reducers/index.js文件中注册store

1
2
3
4
5
6
7
8
9
10
11
// reducersindex.js
......
import one from './one';

const rootReducer = combineReducers({
......
one,
......
});

export default rootReducer;

绑定store和actions到组件

这里我们需要修改开始创建的Home.js组件。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
import React, { Component } from 'react';
import { bindActionCreators } from 'redux';
import { connect } from 'react-redux';
import * as OneActions from '../actions/one';

class Home extends Component {
componentWillMount() {
this.props.getone() //发起action操作
}
render() {
return (
<div>
这是主页
</div>
)
}
}

/* 映射store中的state到组件中 */
function mapStateToProps(state) {
return {
one: state.one
};
}

/* 映射actions到组件中,并且注入dispatch方法 */
function mapDispatchToProps(dispatch) {
return bindActionCreators(OneActions, dispatch);
}

/* 修改组件导出方式,导出调用connect方法生成后的新组件*/
export default connect(mapStateToProps, mapDispatchToProps)(Home);

这里注入的state与actions都可以通过this.props访问到。这时打开浏览器可以看到我们在one action中的getone方法打印出的异步请求数据
response

将异步数据写入到state

修改actions当中的one.js,在拿到数据后dispatch到reducer处理

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
// actions/one.js
import 'whatwg-fetch';
export const UPDATE_ONE = 'update_one';

export function update(_data) {
return {
type: UPDATE_ONE,
data: _data
};
}

export function getone() {
return dispatch => {
fetch('http://v3.wufazhuce.com:8000/api/hp/bymonth/2016-09').then((response) => {
console.log(response)
return response.json()
}).then((data) => {
/** 返回的json格式为
{
res: 0,
data: [...]
}
*/
dispatch(update(data.data[0]))
})
};
}

由于fetch库提供Promise的支持,所以可以使用then结构。

在redux开发工具中我们可以看到如下显示

reduxtool

在末尾处可以看到state中的one已经有数据了,接下来我们将数据绑定到界面组件。

绑定store中的state数据到react组件

回到还是创建的Home.js组件中,我们将需要的数据绑定到界面中

1
2
3
4
5
6
7
8
9
10
11
12
13
......
render() {
const { one } = this.props
return (
<div>
<h2>{one.hp_content}</h2>
<hr/>
<p>{one.hp_author}</p>
<img src={one.hp_img_url}></img>
</div>
)
}
......

这是浏览器里面的页面已经有数据了

perview

经过一些简单的css样式调整得到的效果如下

one

结语

这篇文章讲述了react搭配redux的基础用法,关于react-router的部分本文没有详细讲解,但是react-router的难度也不大,上手也很快。如果需要使用webpack ensure按需加载,需要将组建导出格式换成CommonJS规范导出

1
2
3
4
5
module.exports = React.createClass({
render() {
<div>示例页面</div>
}
})

详细可以参考react-router示例程序