Angular 2 更新全局状态作为更新特定状态的副作用

Angular 2 update global state as a side effect of updating a certain state

我想实现设置全局状态,同时还从 api 请求数据并将其存储在状态中,但在全局状态之外的另一个位置。

我调用这个效果 (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 (global.reducer.ts) 发送调用:

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;
  }
}

这意味着我在发出 http 请求之前和之后更新全局状态 isLoading。然而,这个解决方案既混乱又不起作用,因为它破坏了效果这一简单事实(无论出于何种原因,我认为这是因为我在效果中调用了调度)。

最好我想创建另一个效果来监听 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}))

但这有两个问题:

  1. 我不知道如何在效果中访问已发送的负载。
  2. 我不知道如何从 models$ 效果中调用该效果。

总的来说,我真的很困惑如何实现我想要的,而且就我所能找到的而言,没有任何这方面的例子。

如果你看这张图,我想在更新models时更新global.isLoading:

实现我想要的最好方法是什么?

isLoading 指标存储在中央位置类似于有时对错误信息所做的操作。一个 涉及使用忽略操作类型的缩减器,只查看它们是否包含 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;
    }
}

isLoading 使用 boolean 值假设您不会有并发的异步效果,所以如果这是一个问题,您可以扩展减速器以使用计数器。

如果您以这种方式连接,isLoading 指标不需要知道任何关于单个效果的信息,反之亦然。