function injectModel(createReducer, onError, unlisteners, m) {
model(m);
var store = app._store;
if (m.reducers) {
store.asyncReducers[m.namespace] = (0, _getReducer2.default)(m.reducers, m.state);
store.replaceReducer(createReducer(store.asyncReducers));
}
if (m.effects) {
store.runSaga(app._getSaga(m.effects, m, onError, plugin.get('onEffect')));
}
if (m.subscriptions) {
unlisteners[m.namespace] = (0, _subscription.run)(m.subscriptions, m, app, onError);
}
}
这个函数里面调用了上面的 model() ,除此之外,该函数还将 model 定义的 reducers,effects, subscriptions 进行分别处理。
reducers 分支 是调用 redux 的原生 api 对 model 中的 reducers 进行处理
dva 初探
什么是 dva
dva是基于现有应用框架(
redux
+react-router
+redux-saga
等)封装的一个框架(不是库),基本上没有引入新概念,也没有创建新语法,对于熟悉前言中涉及的技术栈的童鞋来说会非常容易上手。详细介绍可移步dva介绍为什么会有 dva
在处理复杂异步请求的业务中,一开始我们是使用 redux-thunk + async/await 结合使用,比如在异步登录的逻辑中,使用 redux-thunk 处理如下:
这种处理之后,组件调用的是
dispatch(action creator)
,此时的 action 被赋予了太多的逻辑功能,不再是一个 pure action 。为了保持 action 的简洁性,继而引入 redux-saga ,它提供了一个 saga 文件用来存放异步逻辑,引入 redux-saga 之后,上面的验证用户登录逻辑就变成如下:使用 redux-saga 之后,action 又回归其纯粹性。并且将异步操作全部抽离在 sagas 中一层进行处理,这样方便我们进行多种异步处理操作。 redux-saga 虽然在处理较为复杂的异步逻辑时提供了比较好的解决方案,但是当业务变复杂时,随着模块的逐渐增加,由于项目通常要分 reducer, action, saga, component 等等,所以项目中的文件个数也会变得很多,如下:
这样在项目开发过程中,就需要不断地切换文件目录,大大影响开发效率。于是 dva 应运而生,dva 的主要解决的项目开发中的痛点:
上面的例子使用 dva 来实现如下:
其中,reducers 可以看成是同步的请求逻辑,effects 可以看成是异步的请求逻辑,所有的逻辑都放在了 models 目录下的文件中,省去了文件之间的切换成本,让开发人员可以专注于业务逻辑。 具体可以参考支付宝前端应用架构的发展和选择
dva 的相关知识点
dva中只有5个 API,8个新的概念,其中所有的 API 如下:
app = dva(Opts)
创建应用,返回 dva 实例app.use(Hooks)
配置 hooks 或者注册插件app.model(ModelObject)
注册 modelapp.router(Function)
注册路由表app.start([HTMLElement], opts)
启动应用具体的使用可以移步这里
8个概念如下所示:
调用的时候有如下两种方式:
dispatch(Action);
dispatch({ type: 'todos/add', payload: 'todo content' });
dva 的使用
如何基于 dva 开发一个项目,dva 的作者给出了一个一步步开发 dva 项目的教程, 笔者仿照该教程,并且基于 dva2.0, 做出了一个 demo,该 demo 类似于 dva中的范例,只是初步体验一下 dva 的开发。
深入 dva
借用描述 dva 数据流动的一张图,如下所示:
如图所示:用户在浏览器中访问某个 URL,由此渲染一个页面,该页面可能包含多个 Components, 当用户在页面进行操作的时候,由此 dispatch 某个 action,同步的 action 逻辑放在 Reducer 中,异步的 action 逻辑存放在 Effect 中。通过 model 中的数据处理,将新的 state 传入页面中,从而触发页面数据的更新。
dva 源码解读
这次的解读主要是针对 dva@2.1 和 dva-core@1.1。
首先是 dva 中的入口文件所暴露出来的方法,主要是
const app = dva();
这行代码的作用,返回一个 app实例。该方法如下:这个函数很简单,主要是调用了 dva-core 里面的 create 方法,并且返回了一个包含如下方法的 app 对像:
对 app 的初始化定义在
dva-core/lib/index.js
文件中。在这个文件中,实现了 app 对象的所有方法。接下来一个一个进行分析:其实 app.model 在调用 app.start 之后会变成
injectModel()
, 它的源码如下:这个函数里面调用了上面的 model() ,除此之外,该函数还将 model 定义的 reducers,effects, subscriptions 进行分别处理。
sagaMiddleware.run()
来执行管理一部 action,在这之前,先调用了app._getSaga()
方法:这个方法主要实现了 saga 那一套的
watch/worker
(监听->执行) 的工作形式。