2016-11-08 86 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指示器不需要知道任何有关个别效果的信息,反之亦然。