2016-11-08 38 views
2

我想要實現設置全局狀態,同時也從api請求數據並將其存儲在狀態中,但是在全局狀態以外的另一個位置。Angular 2作爲更新某個狀態的副作用更新全局狀態

我打電話這種效果(models.effects.ts):

@Effect() models$: Observable<Action> = this.actions$ 
    .ofType(GET_MODELS) 
    .switchMap(() => this.modelsApi.getModels()) 
    .map(models => ({type: SET_MODELS, payload: models})) 
    .catch((err: any) => Observable.of({type: GET_FAILURE, payload: {error: err}})) 

現在我想做的事情是這樣的:

@Effect() models$: Observable<Action> = this.actions$ 
    .ofType(GET_MODELS) 
    .do(() => this.store.dispatch({type: 'SET_LOADING_STATE', payload: true})) 
    .switchMap(() => this.modelsApi.getModels()) 
    .map(models => ({type: SET_MODELS, payload: models})) 
    .do(() => this.store.dispatch({type: 'SET_LOADING_STATE', payload: false})) 
    .catch((err: any) => Observable.of({type: GET_FAILURE, payload: {error: err}})) 

正如你可以看到我們派出一個電話在globalReducer(​​):

export const GlobalReducer: ActionReducer<any> = (state: IGlobalStorage = {isLoading: false}, action: Action) => { 

    switch(action.type) { 

    case SET_LOADING_STATE: return Object.assign({}, state, { 
     isLoading: action.payload 
    }); 

    default: return state; 
    } 
} 

這意味着塔t我們在發出http請求之前和之後更新全局狀態isLoading。然而,這個解決方案既混亂又不起作用,因爲它打破了效果這個簡單的事實(無論出於何種原因,我認爲這是因爲我在調用中調用了dispatch)。

最好我想創建另一個效果,它傾聽SET_LOADING_STATE然後調用globalReducer本身,而不是讓models$效果直接做。

像這樣的東西(從內global.effects.ts):

@Effect() loadingState$: Observable<Action> = this.actions$ 
    .ofType(SET_LOADING_STATE) 
    .do(() => ({type: SET_LOADING_STATE, payload: thePayloadThatWasSent})) 

但也有2個問題與:

  1. 我不知道如何在一個效果訪問發送有效載荷。
  2. 我不知道如何從models$效果中調用該效果。

總的來說,我只是很困惑如何實現我想要的,並且根據我所能找到的,沒有任何這方面的例子。

如果你看一下這個圖片,我想更新global.isLoading當我更新models

redux dev tools

什麼會達到我想要的東西的最佳方式?

回答

3

isLoading指標存儲在中心位置與有時用錯誤信息進行的操作類似。一個solution for storing a central error涉及使用忽略動作類型的減速器,並只查看它們是否包含error屬性。

如果您要爲效果的動作類型採用合適的命名方案,您可以使用isLoading做同樣的事情。

一種可能的命名方案可能是:

SOME_ACTION_REQUEST 
SOME_ACTION_RESPONSE 
SOME_ACTION_ERROR 

有了這樣的方案,下面的減速將審查的動作類型,並據此設置isLoading狀態:

export function isLoadingReducer(state: boolean = false, action: Action): boolean { 

    if (/_REQUEST$/.test(action.type)) { 
     return true; 
    } else if (/(_RESPONSE|_ERROR)$/.test(action.type)) { 
     return false; 
    } else { 
     return state; 
    } 
} 

使用了booleanisLoading假設你不會有併發的異步效果,所以如果這是一個問題,你可以擴展reducer來使用計數器。

如果通過這種方式進行連接,isLoading指示器不需要知道任何有關個別效果的信息,反之亦然。