Dva.js 里面的几个概念
和官网的内容基本一致,自己照着写了一遍加深印象,再对照着项目过一遍,对dva.js 以及 umi的理解更深刻了一点
Models
State
type State = any
State表示model的数据状态,通常表现为一个javascript对象(当然可以是any type of state)
操作的时候都要当作是immutable data来对待,保证每次都是全新的对象,没有引用完全没有关系,这样才能保持state的独立性,便于测试、追踪和变化
在dva里面我们可以通过dva的实例属性_Store来看到顶部的state数据,但是通常根本用不到。
const app = dva();
console.log(app._store);
Action
type AsyncAction = any
Action是一个普通的javascript对象,它是改变state的唯一途径。无论是用UI事件、网络回调,还是WebSocket等数据源所获得的数据,最终都会通过dispatch函数调用一个action,从而改变对应的数据。action必须带有 type
属性制定明确具体的行为,其它的字段可以自定义。如果要发起一个action需要使用dispatch
函数,需要注意的是 dispatch
是组件connect Models以后,通过props传入的
dispatch({
type: 'add',
});
Dispatch函数
type dispatch = (a: Action) => Action
dispatching function 是一个用于触发action的函数,action是改变state的唯一途径。但是它只描述了一个行为,而dispatch可以看作是触发这个行为的方式,而Reducer则是描述如何改变数据的。
在dva里面,connect Model的组件通过props可以访问到dispatch,可以调用Model中的Reducer或者Effects,常见的形式如:
dispatch({
type: 'user/add',
payload{}
})
Reducer
type Reducer<S, A> = (state: S, action: A) => S
Reducer(也称为reducing function), 函数接受两个参数:之前已经累计运算的结果和当前要被累积的值,返回的是一个新的累积结果。该函数把集合归并成单独的一个值。
Reducer 的概念来自于是函数式编程,很多语言中都有 reduce API。如在 javascript 中:
[{x:1}, {y: 2}, {z: 3}].reduce(function(prev, next) {
return Object.assign(prev, next)
})
在dva中,reducers聚合积累的结果是当前model的state对象。通过actions中传入的值,与当前reducers中的值进行运算获得新的值(也就是新的state)。需要注意的是reducer必须是纯函数,所以同样的输入获得的一定是同样的输出,它们不应该产生任何的副作用。并且,每一次的计算都应该使用immutable data,这种特性简单理解就是每次操作都是返回一个全新的数据(独立、纯净),所以热重载和事件旅行这些功能才能够使用。
Effect
Effect 被称为副作用,在我们的应用里面,最常见的就是异步操作。它来自于函数编程的概念,之所以叫副作用是因为它使我们的函数变得不纯,同样的输入不一定获得同样的输出。
dva为了控制副作用的操作,底层引入了redux-sagas做异步流程的控制,由于采用了generator的相关概念,所以将异步转换为同步的写法,从而将effects转换为纯函数。
Subscription
Subscriptions 是一种从 源 获取数据的方法,它来自于elm(???黑人)
Subscriptions语义是订阅,用于订阅一个数据源,然后根据条件 dispatch 需要的 action。数据源可以是当前的时间、服务器的 websocket 连接、keyboard 输入、 geolocation变化、 history路由变化等等。
import key from 'keymaster'
...
app.model({
namespace: 'count',
subscriptions: {
keyEvent({dispatch}) {
key('⌘+up, ctrl+up', () => { dispatch({type:'add'}) });
}
}
})
Router
这里的路由通常指的是前端路由,由于我们的应用现在通常是单页面应用,所以需要前端代码来控制路由逻辑,用过浏览器提供的 history API 可以监听浏览器url的变化,从而控制路由相关的操作。
dva实例提供了 router 方法来控制路由,使用的是react-router
import { Router, Route } from 'dva/router';
app.router(({history}) => (
<Router history={history}>
<Route path="/" component={HomePage} />
</Router>
))
Route Components
在组件设计中,我们提到过 容器组件 Container Components, 在 dva 里面我们通常将其约束为 Route Components, 因为在dva里面我们通常以页面维度来设计 Container Components。
所以在 dva 中,通常需要 connect Model的组件都是 Route Components,组织在/routes/
目录下,而/components/
目录下则是纯组件(Presentational Components)。