dva.js是一套数据流的解决方案,其结合了redux的redux-saga异步流的处理方式,dva通过model的概念把一个领域的模型管理起来,包含同步更新 state 的 reducers,处理异步逻辑的 effects,订阅数据源的subscriptions。

1.model的基本配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
export default{
namespace: 'myModel',
state: {

},
subscriptions: {

},
effects: {

},
reducers: {

}
}

namespace: model里面全局的命名空间
state: 初始全局状态值
subscriptions: 数据订阅源
effects: 异步数据流处理
reducers: 同步更新state

2.subscriptions数据订阅

subscriptions可以监听从源头获取数据,数据源可以是当前的时间、服务器的 websocket 连接、keyboard 输入、geolocation 变化、history 路由变化等等,这里演示监听浏览器url和键盘数据案例。

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
/**/ 1.键盘事件
subscriptions: {
keyEvent({dispatch}) {
key('enter', () => { dispatch({type:'add'}) });
},
}
/**/ 2.监听普通url(不带参数)
subscriptions: {
setup({ dispatch, history }) {
return history.listen(({ pathname, query }) => {
if(pathname === "/"){
dispatch({type: 'add'})
}
}
},
}
/**/ 3.监听带参数的url(带参数)
//匹配带参数的url需要依赖一个npm包 path-to-regexp
import pathToRegexp from 'path-to-regexp'
subscriptions: {
setup({ dispatch, history }) {
return history.listen(({ pathname, query }) => {
const reviewMatch = pathToRegexp('/user/:id').exec(pathname)

if (reviewMatch && reviewMatch[0].includes('/user') && reviewMatch[1]) {
const id = reviewMatch[1]
dispath({type: 'add', payload: { data: id }})
}
}
},
}

2.reducers同步更新state

这里演示同步更改state数据,和组合state数据(用于下拉加载),假设model初始化了一个state为dateInfo,此时涉及到三种情况:router页面上同步更改state,subscriptions里面更改state和effects里面更改state。

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
reducers: {
combineData(state, action){
const {payload} = action
const {dateInfo} = state

if (!payload || !Array.isArray(payload)) return {...state}

return {
...state,
dateInfo: [...dateInfo, ...payload]
}
},
change(state, action) {
const {payload} = action
if (!payload.name) return {...state}
return {
...state,
[payload.name]: payload.value
}
},
}
/**/ 1.router页面上更改state,需要调用this.props.dispatch()方法
//需要在action前加入对应的命名空间
this.props.dispatch({
type: 'myModel/change',
payload: {
name: 'count',
value: 0
}
})
/**/ 2.subscriptions里面更改state
//直接subscriptions里面的dispatch方法,详细看第2小节
dispatch({
type: 'change',
payload: {
name: 'count',
value: 0
}
})
/**/ 3.effects里面更改state
//effects里面使用Generator函数实现异步流处理,利用参数的put方法,Generator函数使用详见第3小节
yield put({
type: 'change',
payload: {
name: 'count',
value: 0
}
})

3.effects异步处理数据流

effects用于处理异步数据,采用Generator函数,yield关键字使生成器函数执行暂停,上一个yield执行完毕后在执行下一个yield,假设model初始化了一个state为dateId,此时涉及到三种情况:router页面调用异步处理,subscriptions调用异步处理和effects内部调用。

假设我们导入对应的request请求

1
import {getUserLists} from '../services/getUserLists'

router页面调用和subscriptions调用建立在effects函数之上

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
/**/ 1.effects函数和effects内部调用
//effects采用Generator函数
/**
* { payload }为调用该异步处理函数时传入的payload函数 比如:this.props.dispatch({type: 'myModel/getFetchData', payload: 'params'})
* { call }用于执行异步函数,调用异步请求
* { put }触发一个同步请求,reducer里面的action,类似于dispatch
* { select }从全局model中选择state 比如: const {dateInfo} = yield select(state => state.myModel) 也可以是其他命名空间
**/
*getUserLists({ payload }, { call, put, select }){
const { dateId } = yield select(state => state.myModel)

const data = yield call(getUserLists, 'get', {
id: dateId || 0,
})

if (!data) return

yield put({type: 'change', payload: {name: 'dataInfo', value: data}})
}

/**/ 2.router页面调用异步处理
//使用this.props.dispatch,加上命名空间
this.props.dispatch({type: 'myModel/getUserLists', payload: 'params'})

/**/ 3.subscriptions调用异步处理
//使用dispatch
dispatch({ type: 'getUserLists', payload: 'params' })

使用dva.js小结附加

1.避免数组取值报错,对数据进行判断
1
2
3
4
// 假设有数组 arr,需要对其进行遍历
Array.isArray(arr) && arr.length && arr.map(x => {
// do someting
})
2.JSX语法嵌套
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// 假设需要在react元素里面嵌套js,js里面返回react元素,react元素里面再使用js
//...以上代码省略
render(){
return(
<div>
<ul>
{
Array.isArray(arr) && arr.length && arr.map((v, i) => {
return (<li key={i} style={{fontSize: '20px', color: `${ v=== '特定值' ? 'red' : 'black' }`}}>值为{v}</li>)
})
}
</ul>
</div>
)
}
//...以下代码省略
3.使用esLint校验的项目应使用===,不然会报warnings
4.sass预处理,封装通用的sass

按照750的设计稿标准

1
2
3
4
5
6
$baseFontSize: 7.5;
$basisColor: #FFC107;

@function pxToVw($px) {
@return $px / $baseFontSize * 1vw;
}
5.全局定时器的使用

需要在组件挂载完毕的生命周期函数里面调用定时器,需要在组件将要卸载的生命周期函数清除定时器。