Angular 2更新全局状态是更新特定状态的副作用 [英] Angular 2 update global state as a side effect of updating a certain state

查看:92
本文介绍了Angular 2更新全局状态是更新特定状态的副作用的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想设置全局状态,同时还要从api请求数据并将其存储在该状态中,但要存储在全局状态以外的其他位置.

I want to achieve setting a global state while also requesting data from an api and storing that in the state as well, but in another location than the global state.

我称这种效果(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}}))

现在我想做的是这样的:

Now what I want to do is something like this:

@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)的呼叫:

As you can see we're dispatching a call to the 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.但是,此解决方案既麻烦又行不通,因为它破坏了效果这一简单事实(无论出于何种原因,我认为这是因为我在效果内调用了dispatch).

Which would mean that I update the global state isLoading before and after we make an http request. However, this solution is both messy and does not work because of the simple fact that it breaks the effect (for whatever reason, I think it's because I call dispatch within the effect).

最好是我想创建一个监听SET_LOADING_STATE的效果,然后调用globalReducer本身,而不是让models$效果直接实现.

Preferably I would like to create another effect which listens to SET_LOADING_STATE which then calls the globalReducer itself, rather than letting the models$ effect do it directly.

类似的事情(在global.effects.ts中):

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

但是有两个问题:

  1. 我不知道如何访问效果中发送的有效载荷.
  2. 我不知道如何从models$效果中调用该效果.
  1. I don't know how to access a sent payload in an effect.
  2. I don't know how to call that effect from within the models$ effect.

总的来说,我对如何实现自己想要的东西感到非常困惑,据我所知,还没有任何示例.

Overall I'm just really confused on how to achieve what I want and there aren't any examples of this as far as I've been able to find.

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

If you look at this image, I want to update global.isLoading when I update models:

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

What would be the best way to achieve what I want?

推荐答案

isLoading指示符存储在中央位置类似于有时使用错误信息进行的操作.一种用于存储中心错误的解决方案涉及使用化简器,该化简器会忽略操作的类型,仅查看它们是否包含error属性.

Storing an isLoading indicator in a central place is a similar to what is sometimes done with error information. One solution for storing a central error involves using a reducer that ignores actions' types and looks only to see if they contain an error property.

如果要为效果的动作类型采用合适的命名方案,则可以使用isLoading做很多相同的事情.

If you were to adopt a suitable naming scheme for your effects' action types, you could do much the same thing with isLoading.

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

One possible naming scheme could be:

SOME_ACTION_REQUEST
SOME_ACTION_RESPONSE
SOME_ACTION_ERROR

使用这种方案,以下减速器将检查动作类型并相应地设置isLoading状态:

With such a scheme, the following reducer would examine the action types and set the isLoading state accordingly:

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值假定您没有并发异步效果,因此,如果出现问题,可以扩展reducer使其使用计数器.

Using a boolean value for isLoading assumes that you would not have concurrent asynchronous effects, so if that's an issue, you could extend the reducer to use a counter instead.

如果您通过这种方式进行连接,则isLoading指示器不需要了解有关单个效果的任何信息,反之亦然.

If you wire things up this way, the isLoading indicator doesn't need to know anything about individual effects and vice versa.

这篇关于Angular 2更新全局状态是更新特定状态的副作用的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆