近期開發項目,使用 sword UI 框架(基於 react、antd、umi、dva)。對於其中 loading 狀態的控制,很感興趣,特地查詢了相關資料,進行學習。sword 中 loading 狀態 主要是使用了 dva-loading 來控制;javascript
經過使用@connect 語法糖來說 model 和 component 綁定起來,其中 loading 是一個含有 global、models、effects 三個鍵值的對象;java
@connect(({ quote, loading }) => { quote, loading:{global,models,effects} // loading 對象中相關參數 // { // global: false, //當前項目任一models有數據請求行爲的時候,global 爲true,沒有請求的時候爲false // models:{ // quote: false //當前項目quote model有數據請求行爲的時候,quote 爲true,沒有請求的時候爲false // }, // effects:{ // 'quote/fetchMyQuoteList': false //當前項目quote model有數據請求行爲的時候,quote 爲true,沒有請求的時候爲false // } // } }) //頁面上 export default class Quote extends React.Component { constructor(props) { super(props); } getQuoteList = async () => { const { dispatch } = this.props; await dispatch({ type: "quote/fetchQuoteList", payload: value }); setTimeout(() => { dispatch({ type: "common/fetch", }); }, 2000); }; render() { return ( // 總體項目 loading狀態控制 <Spin spinning={global}> // quote 頁面loading 狀態控制 <Spin spinning={models.quote}> // 請求table列表接口 loading狀態控制 <Table dataSource={list} loading={effects['quote/fetchQuoteList']} /> <Button onClick={this.queryDATA}>請求</Button> </Spin> </Spin> ); } }
源碼以下 很短react
const SHOW = "@@DVA_LOADING/SHOW"; const HIDE = "@@DVA_LOADING/HIDE"; const NAMESPACE = "loading"; function createLoading(opts = {}) { const namespace = opts.namespace || NAMESPACE; const { only = [], except = [] } = opts; if (only.length > 0 && except.length > 0) { throw Error( "It is ambiguous to configurate `only` and `except` items at the same time." ); } const initialState = { global: false, models: {}, effects: {}, }; const extraReducers = { [namespace](state = initialState, { type, payload }) { const { namespace, actionType } = payload || {}; let ret; switch (type) { case SHOW: ret = { ...state, global: true, models: { ...state.models, [namespace]: true }, effects: { ...state.effects, [actionType]: true }, }; break; case HIDE: { const effects = { ...state.effects, [actionType]: false }; const models = { ...state.models, [namespace]: Object.keys(effects).some((actionType) => { const _namespace = actionType.split("/")[0]; if (_namespace !== namespace) return false; return effects[actionType]; }), }; const global = Object.keys(models).some((namespace) => { return models[namespace]; }); ret = { ...state, global, models, effects, }; break; } default: ret = state; break; } return ret; }, }; function onEffect(effect, { put }, model, actionType) { const { namespace } = model; if ( (only.length === 0 && except.length === 0) || (only.length > 0 && only.indexOf(actionType) !== -1) || (except.length > 0 && except.indexOf(actionType) === -1) ) { return function* (...args) { yield put({ type: SHOW, payload: { namespace, actionType } }); yield effect(...args); yield put({ type: HIDE, payload: { namespace, actionType } }); }; } else { return effect; } } return { extraReducers, onEffect, }; } export default createLoading;
在.umi 被動目錄中,dva 文件中有以下代碼;經過 app.use 引入 dva-loading,其中 createLoading 是 dva-loading 拋出的函數方法;antd
import createLoading from "dva-loading"; app = dva({ history, ...(runtimeDva.config || {}), ...(window.g_useSSR ? { initialState: window.g_initialData } : {}), }); app.use(createLoading());
createLoading 函數返回 含有 extraReducers 和 onEffect 兩個鍵值的對象;
其中,onEffect 方法主要邏輯是 在 dispatch 方法調用前,調用 loading model 中 方法來控制 loading 顯示;dispatch 方法調用後,控制 loading 隱藏;app
extraReducers 方法主要 在 onEffect 方法運行後,去修改相應的 global, models, effects,三個參數,並拋出來;
能夠看到 extraReducers 方法拋出的對象,就是咱們在 component 中,經過@connect 引入 loading 以後,打印的對象;框架