008 dva.js框架
经过一段时间的学习,我们已经能理解redux的概念,也能熟练使用中间件进行异步操作等,这种数据流控制可以让应用更可控也让逻辑更加清晰。
但是带来的问题是:
编辑成本高,需要在
reducer,saga,action之间来回切换redux 的项目通常要分 reducer, action, saga, component 等等,我们需要在这些文件之间来回切换。并且这些文件通常是分目录存放的:
+ src + sagas - user.js + reducers - user.js + actions - user.js1
2
3
4
5
6
7所以通常我们需要在这三个 user.js 中来回切换
不便于组织业务模型 (或者叫
domain model) 。比如我们写了一个userlist之后,要写一个productlist,需要复制很多文件。saga 书写太复杂,每监听一个
action都需要走 fork -> watcher -> worker 的流程function *userCreate() { try { // Your logic here } catch(e) {} } function *userCreateWatcher() { takeEvery('user/create', userCreate); } function *rootSaga() { yield fork(userCreateWatcher); }1
2
3
4
5
6
7
8
9
10
11对于
redux-saga来说,这样设计可以让实现更灵活,但对于我们的项目而言,大部分场景只需要用到takeEvery和takeLatest就足够,每个 action 的监听都需要这么写就显得非常冗余entry 书写麻烦
除了
redux store的创建,中间件的配置,路由的初始化,Provider的store的绑定,saga的初始化,还要处理reducer,component,saga的 HMR 。这就是真实的项目应用redux的例子,看起来比较复杂
基于以上原因支付宝团队封装了 dva 框架
import React from 'react';
import dva, { connect } from 'dva';
import { Route } from 'dva/router';
// 1. Initialize
const app = dva();
// 2. Model
app.model({
namespace: 'count',
state: 0,
reducers: {
['count/add' ](count) { return count + 1 },
['count/minus'](count) { return count - 1 },
},
});
// 3. View
const App = connect(({ count }) => ({
count
}))(function(props) {
return (
<div>
<h2>{ props.count }</h2>
<button key="add" onClick={() => { props.dispatch({type: 'count/add'})}}>+</button>
<button key="minus" onClick={() => { props.dispatch({type: 'count/minus'})}}>-</button>
</div>
);
});
// 4. Router
app.router(
<Route path="/" component={App} />
);
// 5. Start
app.start(document.getElementById('root'));
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
5 步 4 个接口完成单页应用的编码,不需要配 middleware,不需要初始化 saga runner,不需要 fork, watch saga,不需要创建 store,不需要写 createStore,然后和 Provider 绑定,等等。但却能拥有 redux + redux-saga + ... 的所有功能。
参考: