一、概述
以列表頁中的標准列表為主
Ant Design Pro 默認通過只需瀏覽器單方面就可處理的 HashHistory 來完成路由。如果要切換為 BrowserHistory,那在 src/index.js 中也有對應的內容可以直接修改,但需要在后端服務器進行相應路由配置。
二、詳述
加載過程圖
2.1、菜單→路由→組件
在左側的導航欄點擊 列表頁 > 標准列表
后,可以進入到上面截圖所示的頁面。導航欄的內容在 src/common/menu.js
中【或者服務獲取的地址】
菜單:
{ name: '列表頁', icon: 'table', path: 'list', children: [ { name: '查詢表格', path: 'table-list', }, { name: '標准列表', path: 'basic-list', }, //…… ], },
路由
全局的路由關系是:src/index.js
中通過 app.router(require('./router').default);
,將 src/router.js
綁定到 dva
實例的 router
方法上。而在 src/router.js
中又引入了 src/common/router.js
中的 getRouterData
作為數據源。
其實就是相當於:src/common/menu.js
中 path
所指向的路徑對應於 src/common/router.js
中的路由記錄。
export const getRouterData = (app) => { const routerConfig = { ..., '/list/basic-list': { component: dynamicWrapper(app, ['list'], () => import('../routes/List/BasicList')), }, ..., }; ... }
這里調用了同文件內的 lazy-loading 的動態加載函數 dynamicWrapper
,有 3 個參數,app
為全局 dva
實例,models
為一個帶有相關 dva
Model 的 Array,component
即為該路由記錄對應的實際組件。
const dynamicWrapper = (app, models, component) => {...};
可以看到:
1、加載路由的時候,會動態加載當前文件下的model文件,也就是對應文件下的src/models/list.js
組件:
src/routes/List/BasicList.js
,具體組件。已省略部分代碼
import React, { PureComponent } from 'react'; import { connect } from 'dva'; //…… import PageHeaderLayout from '../../layouts/PageHeaderLayout'; @connect(({ list, loading }) => ({ list, loading: loading.models.list, })) export default class BasicList extends PureComponent { componentDidMount() { this.props.dispatch({ type: 'list/fetch', payload: { count: 5, }, }); } render() { return ( <PageHeaderLayout>{/* 頁面內容…… */}</PageHeaderLayout> ); } }
2.2、@connect 裝飾器
組件寫法中調用了 dva
所封裝的 react-redux
的 @connect
裝飾器,用來接收綁定的 list
這個 model 對應的 redux store。注意到這里的裝飾器實際除了 app.state.list
以外還實際接收 app.state.loading
作為參數,這個 loading
的來源是 src/index.js
中調用的 dva-loading
這個插件。
/* * src/index.js */ import createLoading from 'dva-loading'; app.use(createLoading());
它返回的信息包含了 global、model 和 effect 的異步加載完成情況。
數據map一
{ "global": true, "models": { "list": false, "user": true, "rule": false }, "effects": { "list/fetch": false, "user/fetchCurrent": true, "rule/fetch": false } }
注意到在這里帶上 {count: 5}
這個 payload 向 store 進行了一個類型為 list/fetch
的 dispatch,在 src/models/list.js
中就可以找到具體的對應操作。
import { queryFakeList } from '../services/api'; export default { namespace: 'list', state: { list: [], }, effects: { *fetch({ payload }, { call, put }) { const response = yield call(queryFakeList, payload); yield put({ type: 'queryList', payload: Array.isArray(response) ? response : [], }); }, /* ... */ }, reducers: { queryList(state, action) { return { ...state, list: action.payload, }; }, /* ... */ }, };
View中使用
1、connect使用
@connect(({ list, loading }) => ({
list,//①
loading: loading.models.list,//②
}))
說明:
1、connect 有兩個參數,mapStateToProps以及mapDispatchToProps,一個將狀態綁定到組件的props一個將方法綁定到組件的props
2、代碼①:將實體list中的state數據綁定到props,注意綁定的是實體list整體,使用時需要list.[state中的具體變量]
3、代碼②:通過loading將上文“數據map一”中的models的list的key對應的value讀取出來。賦值給loading,以方便使用,如表格是否有加載圖標
當然代碼②也可以通過key value編寫:loading.effects["list/fetch"]
2、變量獲取
因,在src/models/list.js
export default { namespace: 'list', state: { list: [], },
故在view中使用
render() { const { list: { list }, loading } = this.props;
說明:
定義使用時:list: { list } ,含義實體list下的state類型的list變量