参考

这篇博客摘自此处,是从方便自己理解的角度整理了下。

Dva的本质

Dva = React-Router + Redux + Redux-saga

Dva中的数据流向

数据的改变通常是通过用户交互行为或者浏览器行为(如路由跳转等)触发的,当此类行为会改变数据的时候,可以通过dispatch发起一个action,如果是同步行为会直接通过reducers改变State,如果是异步行为(副作用)会先触发Effects然后流向Reducers最终改变State

State

state操作的时候每次都要当做不可变数据来对待,保证每次都是全新的对象,没有引用关系,这样才能保证State的独立性,便于测试和追踪变化。

Action

dispatch函数

Reducer

这个函数接受两个参数:之前已经累积运算的结果和当前要被累积的值,返回的是一个新的累积结果。该函数把一个集合归并成一个单值。感觉这也是Reducer名字的来源。

Effect

这个要好好看看,对这个不太熟悉。

Effect是一个Generator函数,内部使用yield关键字,标识每一步的操作。

Effect被称为副作用,在我们的应用中,最常见的就是异步操作。它来自于函数编程的概念,之所以叫副作用是因为它使得我们的函数变得不纯,同样的输入不一定获得同样的输出。

dva为了控制副作用的操作,底层引入了redux-sagas做异步流程控制,由于采用了generator的相关概念,所以将异步转成同步写法,从而键effects转为纯函数

后面要学的东西:

  1. redux-sagas
  2. generator-将异步转为同步写法
  3. 纯函数好像是个狼人

Subscription

Subscription语义是订阅,用于订阅一个数据源,然后根据条件dispatch需要的action。数据源可以是当前的时间、服务器的websocket连接、keyboard输入、geolocation变化、history路由变化等。

给了一个栗子:

1
2
3
4
5
6
7
8
9
10
import key form 'keymaster';

add.model({
namespace: 'count',
subscriptions: {
keyEvent({dispatch}) {
key('ctrl+up', () => {dispatch({type: 'add'})});
}
}
});

Router

dva实例提供了router方法来控制路由,使用的是react-router。

Route Components

在Dva中,我们将Container Components约束为Route Components,因为在Dva中,我么通常以页面维度来设计Container Components。

所以在Dva中,通常需要connect Mode的组件都是Router Components,组织在/routes/目录下,而/components/目录下则是纯组件。

dva的结构

见这里

  1. 创建应用
  2. 注册Model
  3. 注册视图
  4. 启动应用

关于Model对象

  1. 所有的应用逻辑都定义在app.model这个对象上面

  2. Model对象的属性

    • namespace:当前Model的名称,整个应用的state,由多个小的Model的state以namespace为key合成
    • state:该Model当前的状态。数据保存在这里,直接决定了视图层的输出
    • reducers:Action处理器,处理同步动作,用来算出最新的state
    • effects:Action处理器,处理异步动作

Generator

参考MDN

Calling a generator function does not execute its body immediately; an iterator object for the function is returned instead. When the iterator’s next() method is called, the generator function’s body is executed until the first yield expression, which specifies the value to be returned from the iterator or, with yield*, delefates to another generator function. The next() method returns an object with a value property containing the yielded value and a done property which indicates whether the generator has yielded its last value as a boolean. Calling the next() method with an argument will resume the generator function execution, replacing the yield expression where execution was paused with the arguments from next().