23

我遇到了一个问题,ngrx 商店没有发送一个动作来达到应该处理它的效果。

这是尝试分派的组件:

  signin() {
    this.formStatus.submitted = true;
    if (this.formStatus.form.valid) {
      this.store.dispatch(new StandardSigninAction(this.formStatus.form.value.credentials));
    }
  }

行动:

export const ActionTypes = {
  STANDARD_SIGNIN: type('[Session] Standard Signin'),
  LOAD_PERSONAL_INFO: type('[Session] Load Personal Info'),
  LOAD_USER_ACCOUNT: type('[Session] Load User Account'),
  RELOAD_PERSONAL_INFO: type('[Session] Reload Personal Info'),
  CLEAR_USER_ACCOUNT: type('[Session] Clear User Account')
};

export class StandardSigninAction implements Action {
  type = ActionTypes.STANDARD_SIGNIN;

  constructor(public payload: Credentials) {
  }
}
...

export type Actions
  = StandardSigninAction
  | LoadPersonalInfoAction
  | ClearUserAccountAction
  | ReloadPersonalInfoAction
  | LoadUserAccountAction;

效果:

  @Effect()
  standardSignin$: Observable<Action> = this.actions$
    .ofType(session.ActionTypes.STANDARD_SIGNIN)
    .map((action: StandardSigninAction) => action.payload)
    .switchMap((credentials: Credentials) =>
      this.sessionSigninService.signin(credentials)
        .map(sessionToken => {
          return new LoadPersonalInfoAction(sessionToken);
        })
    );

我可以在调试中看到该组件确实调用了调度方法。我还可以确认StandardSigninAction确实已实例化,因为构造函数中的断点被命中。

但是standardSignin$效果不叫...

什么可能导致不被调用的效果?

如何调试商店内正在发生的事情?

有人可以帮忙吗?

PS我在我的导入中运行上述效果如下:

EffectsModule.run(SessionEffects),

编辑:这是我的 SessionSigninService.signin 方法(确实返回一个 Observable)

  signin(credentials: Credentials) {
    const headers = new Headers({'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8'});
    const options = new RequestOptions({headers: headers});
    const body = 'username=' + credentials.username + '&password=' + credentials.password;
    return this.http.post(this.urls.AUTHENTICATION.SIGNIN, body, options).map(res => res.headers.get('x-auth-token'));
  }
4

5 回答 5

21

这不会是一个明确的答案,但希望它会有所帮助。

在你开始之前:

  • 确保您使用的是最新版本的@ngrx软件包(适用于您正在使用的 Angular 版本)。
  • 如果您更新了任何软件包,请确保重新启动您的开发环境(即重新启动捆绑程序、服务器等)

如果你还没有这样做,你应该看看-的实现,Store这样你就可以对可能出现的问题做出一些有根据的猜测。请注意,Store它很轻。它既是可观察的(使用状态作为源)又是观察者(服从调度程序)。

如果你看一下,store.dispatch你会发现它是 的别名 ,store.next它调用next.Dispatcher

所以调用:

this.store.dispatch(new StandardSigninAction(this.formStatus.form.value.credentials));

应该只看到调度程序发出的动作。

注入到你的效果中的Actionsobservable 也很轻。它只是一个将Dispatcher用作其源的可观察对象。

要查看流经效果的动作,您可以替换为:

@Effect()
standardSignin$: Observable<Action> = this.actions$
  .ofType(session.ActionTypes.STANDARD_SIGNIN)

有了这个:

@Effect()
standardSignin$: Observable<Action> = this.actions$
  .do((action) => console.log(`Received ${action.type}`))
  .filter((action) => action.type === session.ActionTypes.STANDARD_SIGNIN)

ofType不是操作员;这是一种方法,因此要添加do基于日志的日志,需要将其替换为filter.

登录到位后,如果您正在接收操作,则效果的实现存在问题(或者操作类型的字符串/常量可能不是您认为的那样,并且某些内容不匹配)。

如果 effect 没有接收到分派的 action,最可能的解释是store您分派的StandardSigninActionstore您的 effect 使用的不同 - 也就是说,您有 DI 问题。

如果是这种情况,您应该看看与SessionEffects您所说的其他工作有什么不同。(至少你有一些工作,这是一个开始试验的好地方。)他们是从不同的模块分派的吗?是分派StandardSigninAction功能模块的模块吗?

如果您破解其中一个工作SessionEffects以替换其调度的操作,会发生StandardSigninAction什么?然后效果会运行吗?

请注意,此答案末尾的问题不是我想要回答的问题;它们是你应该问自己和调查的问题。

于 2017-03-24T02:17:28.560 回答
12

您的商店的流可能会因为未处理的错误而停止,或者 - 也许更令人困惑的是 - 看起来“已处理”的错误.catch实际上会杀死流,而无需重新发出新的 Observable 以使事情继续进行。

例如,这将终止流:

this.actions$
    .ofType('FETCH')
    .map(a => a.payload)
    .switchMap(query => this.apiService.fetch$(query)
        .map(result => ({ type: 'SUCCESS', payload: result }))
        .catch(err => console.log(`oops: ${err}`))) // <- breaks stream!

但这将使事情保持活力:

this.actions$
    .ofType('FETCH')
    .map(a => a.payload)
    .switchMap(query => this.apiService.fetch$(query)
        .map(result => ({ type: 'SUCCESS', payload: result }))
        .catch(e => Observable.of({ type: 'FAIL', payload: e}))) // re-emit

顺便说一句,任何 rxjs Observable 都是如此,这在向多个观察者广播时尤其重要(就像 ngrx 商店在内部使用 internal 一样Subject)。

于 2017-08-16T20:53:49.767 回答
9

我正在使用更高版本的ngrx(7.4.0),所以cartant的建议是:

.do((action) => console.log(`Received ${action.type}`))

应该...

... = this.actions.pipe(
   tap((action) => console.log(`Received ${action.type}`)),
   ...

最后我发现我错过了将新的效果导出添加到模块中,例如:

EffectsModule.forRoot([AuthEffects, ViewEffects]),  // was missing the ', ViewEffects'
于 2019-07-06T15:27:18.270 回答
2

If you are using version 8, ensure you wrap each action with createEffect.

Example:

Create$ = createEffect(() => this.actions$.pipe(...))
于 2019-11-07T06:11:18.070 回答
0

另一个可能的原因是,如果您使用 ng generate 创建导入效果的模块,请确保将其导入到应用模块中,因为以下命令“ng generate module myModule”不会将其添加到应用模块中。

于 2019-10-03T17:39:05.513 回答