React+Umi3的数据流解决方案-dva
# React+Umi3的数据流解决方案-dva
# 前言
最近初学React,在使用Umi构建项目的过程中,发现官方文档及百度上的各种资料,要么已经过时,要么需要很多的基础。特此记录下我个人对于dva的一些实际使用和理解。以下内容仅作为对官方文档的个人理解,文档有的,复制粘贴没有意义。
# Umi3
读了官网对Umi
的介绍,感觉还是云里雾里。我个人对Umi
的理解是类似于Vue cli脚手架
的项目工具,可以通过配置来获得相应的扩展。目前的体验还是很舒服的。
# dva
社区维护的数据持久层工具,类似VueX
,感觉很相似。
# @umijs/plugin-dva
配置方式
需要手动开启
/config/config.ts
或.umirc.ts
中开启配置
dva: {}
1
# 约定式的model组织方式
所有符合以下规则的文件都会默认是model文件
- scr/models下的文件
- src/pages下,子目录中models目录下的文件
- src/pages下,所有model.ts文件
总结就是,models文件夹的文件和model.ts文件
# model文件--auth.ts
文件
import { Effect, Reducer } from 'umi';
import Request from '@/request/request';
import { auth as AuthApi } from '@/api/index';
import { Toast } from 'antd-mobile';
// 模型状态接口,需要储存什么数据
export interface AuthModelState {
uuid: string;
img: string;
}
// 给状态一个默认值
const initialState = {
uuid: '',
img: '',
};
// 声明模型的类型
export interface AuthModelType {
// 命名空间,可写可不写,不写的话此模型默认是文件名
namespace: 'auth';
// 状态树
state: AuthModelState;
// 异步操作用effects:发送异步请求,定时任务等。需要通过reducers修改状态
effects: {
code: Effect;
login: Effect;
};
// 同步操作,唯一可以直接修改状态的地方
reducers: {
saveCode: Reducer<AuthModelState>;
};
}
// 模型
const AuthModel: AuthModelType = {
namespace: 'auth',
state: initialState,
effects: {
// 使用Generator函数语法来进行异步操作
// 第一个参数是payload,里面有传递的数据
// 第二个参数call,执行异步方法
// 第三个参数put,执行reducers方法
*code({ payload }, { call, put }) {
// 发送请求方法
const getCodeRequest = async () => {
const res = await Request.get(AuthApi.code);
return res;
};
// 执行异步方法
const result = yield call(getCodeRequest);
// 通过put执行reducers方法更新state
yield put({
// type不用写'auth/saveCode',默认是会在本model中找reducers的
type: 'saveCode',
// 传参
payload: {
...result,
},
});
},
*login({ payload }, { call, put }) {
const loginRequest = async () => {
const res = await Request.post(AuthApi.login, { ...payload });
return res;
};
const result = yield call(loginRequest);
if (result.code !== 200) {
Toast.show({
content: result.msg,
});
}
},
},
reducers: {
saveCode(state = initialState, action) {
return {
...action.payload,
};
},
},
};
// 注意导出模型
export default AuthModel;
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
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
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
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
# 组件中使用--login.tsx
文件
// ...
import { ConnectProps, Loading, connect } from 'umi';
import { AuthModelState } from '@/models/auth';
// 从ConnectProps继承,创建本页的Props接口
// ConnectProps中有dispatch方法,用来执行effects或reducers函数
interface PageProps extends ConnectProps {
auth: AuthModelState;
loading: boolean;
}
// 这里的loading就是执行异步时会自动获取到是否加载中状态,会同步更新不用再手动设置和调整了。
const Login: React.FC<PageProps> = ({ auth, loading, dispatch }) => {
// ...
// 更新验证码
const updateCode = () => {
if (dispatch) {
dispatch({
type: 'auth/code',
});
}
};
// 点击了确认登录
const onConfirm = () => {
const params = {
code,
username: userName,
password,
uuid,
};
if (dispatch) {
dispatch({
type: 'auth/login',
payload: params,
});
}
};
// ...
}
// 定义关联参数的类型
type ConnectType = {
auth: AuthModelState;
loading: Loading;
};
export default connect(({ auth, loading }: ConnectType) => ({
auth,
loading: loading.models.auth, // 在models中寻找需要绑定的异步loading。
}))(Login);
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
49
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
49
# subscription
--订阅
model
中的subscription
相当于一个监听器,可以监听路由变化,鼠标,键盘变化,服务器连接变化,状态变化等,这样在其中就可以根据不同的变化做出相应的处理,在这个subsription
中的方法名是随意定的,每次变化都会一次去调用里面的所有方法,所以一边会加相应的判断。
export default {
namespace: 'example',
state: {},
subscriptions: {
// 方法名随意命名,当监听有变化时会依次执行这的变化,
setup({ dispatch, history }) {
window.onresize = () => {
// save是reducer的方法
dispatch( type: 'save' )
}
},
onClick({ dispatch }) {
document.addEventListener('click', () => {
dispatch( type: 'save' )
})
}
},
// ...
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
上次更新: 2/17/2022, 3:13:46 PM