react & dva 全新的WEB应用数据解决方案(一)

准备工作

因为项目涉及到react & dva ,所以首先我们需要安装dva-cli工具去初始化我们的项目,具体的安装方法,网上一大堆,这里不再赘述。有一点需要知道,dva是对redux一种封装,使得我们在处理数据,便于管理,项目结构更加清晰,能够将我们的重点更多的集中业务逻辑的处理上。大大提升开发效率。同时也便于后期数据维护。好了,讲这么多,下面开始实践了;在命令行中输入:

1
2
mkdir dva-dome && cd dva-dome
dva init

至此,我们就得到了一个标准的项目,这个项目的结构为

1
2
3
4
5
6
7
8
9
10
11
12
13
14
·
|———/mock/ #数据mock的接口文件
|———/src/ #项目源码目录
| |—— /components/ #项目组件
| |—— /routes/ #路由组件
| |—— /models/ #数据模型
| |—— /services/ #数据接口
| |—— /utils/ #工具函数
| |—— route.js #路由配置
| |—— index.js #入口文件
| |—— index.less #index样式文件
| |—— index.html
|——— package.json #项目信息
|——— proxy.config.js #数据mock配置

根据后面的注释,我们可以很清晰看出,该脚手架工具,已经为我们做好了很多事。方便简单。那就开始吧

使用antd

通过 npm 安装 antdbabel-plugin-import 。babel-plugin-import 是用来自动引入 antd 的脚本和样式的。

1
npm install antd babel-plugin-import --save

编辑 webpack.config.js,使 babel-plugin-import 插件生效。

1
2
3
4
webpackConfig.babel.plugins.push(['import', {
libraryName: 'antd',
style: 'css',
}]);

设置路由

项目结构有了,接下来,设置路由,首先在.src/router.js里面设置访问路径,接着在/routes/路径下面创建组件User.jsx。代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
// .src/router.js
import React, { PropTypes } from 'react';
import { Router, Route } from 'dva/router';
import Users from './routes/User'
export default function({history}) {
return (
<Router history={history}>
<Route path="/users" component={Users}/>
<Router>
)
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// /routes/User.js
import React, { PropTypes } from 'react';
function User() {
return (
<div>User Router Comonent</div>
)
}
User.PropTypes={
};
export default User;

如此我们便创建了一个路由,其他业务页面路由也是如此创建。
看上去是如此的简单, 那么下面我不得不做工作使得我们组件更加的健壮,OK,GO!继续修改/routes/User.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, { PropTypes } from 'react';
// 业务组件,后面完善,这里占位。
import UserList from '../components/Users/UserList';
import UserSearch from '../components/Users/UserSearch';
import UserModal from '../components/Users/UserModal';
import styles from './User.less';
function User() {
const userSearchProps = {};
const userListProps = {};
const userModalProps = {};
return (
<div className={styles.base}>
{/**用户筛选 */}
<UserSearch {...userSearchProps} />
{/**用户信息列表 */}
<UserList {...userListProps} />
{/**用户弹出层 */}
<UserModal {...userModalProps} />
</div>
)
}
User.PropTypes={
};
export default User;

你会发现,该文件出现了 UserList, UserSearch, UserModal import进来的组件,没错它们就是我们需要的,对照代码中的路径,在对应目录下新建对应的文件,并添加UI 代码。如下:

1
2
3
4
// /components/Users/UserList.js
import React, { PropType } from 'react';
export default ()=><div> 用户列表 </div>

1
2
3
4
// /components/Users/UserSearch.js
import React, { PropType } from 'react';
export default ()=> <div> 用户筛选 </div>
1
2
3
4
// /components/Users/UserModal.js
import React, { PropType } from 'react';
export default ()=> <div> 用户弹出层 </div>

OK! 到此为止,我可以检验一下成果了,启动服务器查看。命令如下:

1
npm start

在浏览中输入localhost:8989/#/User查看。
很开心,我们已经看到了自己做得成果,很好,继续接着往下走,下面我们将把 UserList, UserSearch, UserModal 做成我们想要的样子。 对,看上去就是一脸想要的样子!嘿嘿。。。

UserList组件

有了 UI, 没数据怎么行吗?下面我们会将数据引进到组件里面,做成真正你想 的样子。来修改src/comments/Users/UserList.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
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
import React, { PropType } from 'react';
import { Table, message, Popconfirm } from 'antd';
const UserList = ({
total,
current,
loading,
dataSource,
}) => {
const columns = [{
title: "姓名",
dataIndex: "name",
key: "name",
render: (text) => <a href='javaScript:;'>{text}</a>
}, {
title: '年龄',
dataIndex: 'age',
key: 'age',
}, {
title: '住址',
dataIndex: 'address',
key: 'address',
}, {
title: '操作',
key: 'operation',
render: (text, record) => {
<p>
<a href="javaScript:;" onClick={()=>{}}>编辑</a>
&nbsp;
<Popconfirm title='确定要删除吗?'>
<a href="javaScript:;">删除</a>
</Popconfirm>
</p>
}
}]
const pagination = {
total,
current,
pageSize: 10,
onChange: ()=>{},
}
return (
<div>
<Table
columns={columns}
dataSource={dataSource}
loading={loading}
rowKey={record => record.id}
pagination={pagination}
/>
</div>
)
}
export default UserList;

这里我们借用国内支付宝团队做的一个优秀的 UI 样式库,其实在实际的项目中,我已经有用过该样式库,很方便,很优秀。虽然还没正式发布,但是值得一用。吐血推荐。好吧,这里免费打了一波广告。既然引用antd,所以我们需要在 src/index.js 中添加 import 'antd/dist/antd.css' 引入antd样式库;

模拟数据添加到 UserList 组件

开始编辑 /routes/User.js 文件,跟着流程走,就会发现通过路由拿到数据,然后再传到页面的 UI 元素中。 代码如下:

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
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
import React, { PropTypes } from 'react';
// 业务组件,后面完善,这里占位。
import UserList from '../components/Users/UserList';
import UserSearch from '../components/Users/UserSearch';
import UserModal from '../components/Users/UserModal';
import styles from './User.less';
function User() {
const userSearchProps = {};
const userListProps = {
total: 3,
current: 1,
loading: false,
dataSource: [
{
name: "木见过",
age: 18,
address: "滨江"
}, {
name: "懂得",
age: 18,
address: "滨江"
}, {
name: "生活",
age: 18,
address: "花园"
}, {
name: "琪琪",
age: 18,
address: "北京"
},
]
};
const userModalProps = {};
return (
<div className={styles.base}>
{/**用户筛选 */}
<UserSearch {...userSearchProps} />
{/**用户信息列表 */}
<UserList {...userListProps} />
{/**用户弹出层 */}
<UserModal {...userModalProps} />
</div>
)
}
User.PropTypes={
user: PropTypes.object,
};
export default User;

做完之后就可在页面中查看了,是不是有点意思。好了,继续往下走。谁让我们目标那么的远大呢!这让我想起一句话, 人生不止有狗粮,还有到不了的远方和读不懂的诗,但不管怎么样,一路向西,死也要死在路上。哈哈哈。。。从上面的代码可以看出,我们用的是假数据模拟。接下来玩点高端的,我们将把所有数据在 models 中抽象出来,这样非常便于日后的数据维护。

添加Reducers

这是一个全新的概念,这次接这个做笔记的机会理解一下。dva 中 Reducer 的概念,主要是源于下层封装的 redux, 在 dva 中 reducers 主要负责修改model的数据(state),
看资料得知为什么会叫reducer这个名字,在很多程序中,一个数组都具备reduce这个方法,该方法的功能就是聚合用,例如以下代码:

1
2
3
4
[{x:1},{y:2},{z:3}].reduce(function(prev, next) {
return object.assign(prev, next);
})
// return {x:1, y:2, z:3}

OK, 从上面的代码中我们可以看出,程序将三个对象合成一个对象了。这就是reducer想要达到目的。 如果你了解更多,可以参看‘Redux Reducers’

动手开始给User Model 添加 Reducers

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
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
export default {
namespace: 'user',
state: {
list: [],
tatal: null,
loading: false,
current: null,
currentItem: {},
modalVisible: false,
modalType: 'create',
},
effects: {
*query(){},
*create(){},
*'delete'(){},
*update(){},
},
reducers: {
showLoading(){},
showModal(){},
hideModal(){},
querySuccess(state){
const mock = {
total: 3,
current: 1,
loading: false,
dataSource: [
{
name: "木见过",
age: 18,
address: "滨江"
}, {
name: "懂得",
age: 18,
address: "滨江"
}, {
name: "生活",
age: 18,
address: "花园"
}, {
name: "琪琪",
age: 18,
address: "北京"
},
],
};
return {...state, ...mock, loading: false};
},
createSuccess(){},
deleteSuccess(){},
updateSuccess(){},
}
}

OK,上面的代码中,我们已经将原来模拟的静态数据迁移到models的 reducers 里面了,但是这还不够,我们需要将数据和UI组件关联起来。下面干死它。

关联Modal

当组件和 Model 建立了关系之后,我们还需要去调用一下 Reducers 的,就是需要在组件发起一个action。直接看代码:

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
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
import { hashHistory } from 'dva/router';
export default {
namespace: 'user',
state: {
list: [],
tatal: null,
loading: false,
current: null,
currentItem: {},
modalVisible: false,
modalType: 'create',
},
// 订阅数据
subscriptions: {
setup({ dispatch, history }) {
history.listen(localtion => {
if(localtion.pathname === '/User') {
dispatch({
type: 'querySuccess',
payload: {},
})
}
})
}
},
effects: {
*query(){},
*create(){},
*'delete'(){},
*update(){},
},
reducers: {
showLoading(){},
showModal(){},
hideModal(){},
querySuccess(state){
const mock = {
total: 3,
current: 1,
loading: false,
dataSource: [
{
name: "木见过",
age: 18,
address: "滨江"
}, {
name: "懂得",
age: 18,
address: "滨江"
}, {
name: "生活",
age: 18,
address: "花园"
}, {
name: "琪琪",
age: 18,
address: "北京"
},
],
};
return {...state, ...mock, loading: false};
},
createSuccess(){},
deleteSuccess(){},
updateSuccess(){},
}
}

上面的代码中,我们是在一个页面初始化的时候发出 action 获取数据,然后渲染到页面中。奥,对了,还有一点需要注意一下,当你定义好了 modal 之后,千万别忘了在 src/index.js 引入该数据模型,然后就爽歪歪了,代码如下:

1
app.model(require('./models/users'));

本章小结

写到这里,其实大部分已经写完了,所以我们需要理一下思路比较好。

  1. 首先我们在 src/components 新建文件夹 Users 用来存放所有与用户信息相关的组件,在的该文件下新建了3个 UI 组件去描述用户信息。
  2. UI 组件新建好了, 接下来去路由文件夹 /routes/ 文件夹下面,新建路由组件,并且引入之前下的3个 UI 组件。
  3. 路由组件写好之后,我们就可以配置路由了,OK,找到 src/router.js 添加该Web页面的路由,具体代码请查看本文前部分。
  4. 好像所有准备工作都做好了,剩下的就是核心了, 数据, 找到 models 文件夹然后,新建数据 users.js,去处理数据。具体源码见上文。
  5. 这篇文章中,我们只是模拟了静态数据,实际的业务逻辑都是请求接口,是异步操作,在请求拿到数据后,怎么去更新state, 下面将会讲到。
Fork me on GitHub