背景
ant-design-pro升级到v4后对于动态加载菜单非常友好,只需对src/layouts/BasicLayout.tsx
中的menuDataRender进行改造就行。官方文档有说明,但是并不能直接拿来用,对于新手并不能立马实现。
使用fetch进行动态加载菜单
- 首先
const [menuData=[], setMenuData] = useState([]);
menuData需要给一个默认的空数组,这样才不会导致当menuData数据还未加载成功的时候,获取面包屑映射出现异常。 给了默认值之后,在useEffect中进行http请求,
1
2
3
4
5
6
7useEffect(() => {
fetch('/api/getMenuData')
.then(response => response.json())
.then(data => {
setMenuData(data || []);
});
}, []);然后修改menuDataRender方法就可以实现动态加载菜单数据了。
1
2
3
4
5
6
7return (
<ProLayout
...
menuDataRender={() => menuData}
...
/>
);菜单格式MenuDataItem
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[
{
path: '/dashboard',
name: 'dashboard',
icon: 'dashboard',
children: [
{
path: '/dashboard/analysis',
name: 'analysis',
exact: true,
},
{
path: '/dashboard/monitor',
name: 'monitor',
exact: true,
},
{
path: '/dashboard/workplace',
name: 'workplace',
exact: true,
},
],
}
....
]
使用dva dispatch来加载数据(官方推荐)
- 创建model,在src/models目录下新建menu.ts,内容如下。
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
45import { getMenuData } from '@/services/menu';
import { Effect } from 'dva';
import { Reducer } from 'redux';
import {MenuDataItem} from "@ant-design/pro-layout";
export interface MenuModelState {
menuData?: MenuDataItem[];
}
export interface MenuModelType {
namespace: 'menu';
state: MenuModelState;
effects: {
getMenuData: Effect;
};
reducers: {
saveMenu: Reducer<MenuModelState>;
};
}
const MenuModel: MenuModelType = {
namespace: 'menu',
state: {
menuData: [],
},
effects: {
*getMenuData({ payload, callback }, { call, put }) {
const response = yield call(getMenuData);
yield put({
type: 'saveMenu',
payload: response,
});
},
},
reducers: {
saveMenu(state, action) {
return {
...state,
menuData: action.payload || [],
};
},
},
};
export default MenuModel; 创建service,在src/services目录下,创建menu.ts,内容如下。
1
2
3
4
5import request from '@/utils/request';
export async function getMenuData(): Promise<any> {
return request('/menu/menuData');
}创建mock数据,我这里就不重新创建menu单独的文件了,直接把mock数据写在了route.ts文件里面。
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
31export default {
...
'Get /menu/menuData': [
{
path: '/dashboard',
name: 'dashboard',
icon: 'dashboard',
children: [
{
path: '/dashboard/analysis',
name: 'analysis',
exact: true,
},
{
path: '/dashboard/monitor',
name: 'monitor',
exact: true,
},
{
path: '/dashboard/workplace',
name: 'workplace',
exact: true,
},
],
}
],
...
};现在我们model已经准备好了,就剩model和view关联的问题了,那么BasicLayout.tsx如何加载后台数据呢?。初学dva和react的我,对于connect掌握的不是很熟练,于是我就先根据currentUser加载方式写了一遍,其中需要注意的东西是非常的多。
首先找到connect的mapStateToProps,在BasicLayout.tsx的末尾。如果直接加上menu是会报错的,因为ConnectState中并没有menu类型。
1
2
3
4
5export default connect(({ global, settings, menu}: ConnectState) => ({
collapsed: global.collapsed,
settings,
menuData:menu.menuData,
}))(BasicLayout);所以我们找到ConnectState增加
menu: MenuModelState;
其中 menu 就是我们刚刚model中的namespace,如果此处名字和namespace不对应会导致数据加载不上了,非常重要;MenuModelState 也是在menu的model中定义的。1
2
3
4
5
6
7export interface ConnectState {
global: GlobalModelState;
loading: Loading;
settings: SettingModelState;
user: UserModelState;
menu: MenuModelState;
}ConnectState和mapStateToProps设置好之后,数据就到了props中,由于ProLayout中默认有menuData,所以如果props中传入了menuData,那么菜单就会用menuData的数据,而不是route的数据,至此动态菜单渲染成功。