Angular 2更新全局状态是更新某个状态的副作用

时间:2016-11-08 13:14:36

标签: angular rxjs ngrx

我想实现设置一个全局状态,同时也从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}}))

您可以看到我们正在拨打globalReducerglobal.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$效果中调用该效果。
  3. 总的来说,我真的很困惑如何实现我想要的东西,而且就我所能找到的而言,没有任何例子。

    如果您查看此图片,我想在更新global.isLoading时更新models

    redux dev tools

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

1 个答案:

答案 0 :(得分:3)

isLoading指标存储在中央位置与有时使用错误信息进行的操作类似。一个the API docs涉及使用忽略动作的减速器。类型和外观只是为了查看它们是否包含error属性。

如果你要为你的效果采用合适的命名方案&#39;动作类型,你可以用isLoading做同样的事情。

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

SOME_ACTION_REQUEST
SOME_ACTION_RESPONSE
SOME_ACTION_ERROR

使用这样的方案,以下reducer将检查操作类型并相应地设置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;
    }
}

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

如果以这种方式连接,isLoading指示器不需要知道任何有关个别效果的信息,反之亦然。