Эффект ngrx не вызывается, когда действие отправляется из компонента

У меня проблема с магазином 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$ не вызван ...

Что может вызвать не вызываемый эффект?

Как я могу отладить то, что происходит в магазине?

Может кто-нибудь помочь?

P.S. Я использую вышеупомянутый эффект в моем импорте следующим образом:

EffectsModule.run(SessionEffects),

edit: вот мой метод 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'));
  }

person balteo    schedule 22.03.2017    source источник
comment
Вы используете самые свежие версии @ngrx библиотек? У вас есть другие эффекты, которые работают? У вас есть другие эффекты в SessionEffects, которые работают?   -  person cartant    schedule 23.03.2017
comment
Да, у меня есть другие эффекты в SessionEffects, которые работают   -  person balteo    schedule 23.03.2017
comment
Может кто-нибудь предложить способы отладки магазина ngrx, эффектов и действий?   -  person balteo    schedule 23.03.2017
comment
Я открыл здесь отдельный вопрос: stackoverflow.com/questions/42985102   -  person balteo    schedule 23.03.2017
comment
Ваш магазин доступен как state => state.root.mystore или прямо как state.root. Включили ли вы эффекты в app.module.ts EffectsModule.forRoot([MyFirstEffects, MySecondEffects]), эти вопросы уже задавали мне вопросы.   -  person ldgorman    schedule 27.07.2018


Ответы (5)


Это не будет окончательным ответом, но, надеюсь, он будет полезным.

Прежде чем ты начнешь:

  • Убедитесь, что вы используете последние версии пакетов @ngrx (которые подходят для используемой вами версии Angular).
  • Если вы обновили какие-либо пакеты, обязательно перезапустите среду разработки (то есть перезапустите сборщик, сервер и т. Д.)

Если вы еще этого не сделали, вам следует взглянуть на реализация Store - чтобы вы могли предположить, что может пойти не так. Обратите внимание, что Store довольно легкий. Это и наблюдаемый (использующий состояние в качестве источника), и наблюдатель (который подчиняется диспетчеру).

Если вы посмотрите на store.dispatch, вы Вы увидите, что это псевдоним для _5 _, который вызывает next в _7 _.

Так зовут:

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

должен просто увидеть действие, испущенное диспетчером.

Наблюдаемое Actions, которое вводится в ваш эффекты тоже довольно легкие. Это просто наблюдаемое, которое использует 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.

Если при ведении журнала вы получаете действие, то что-то не так с реализацией эффекта (или, возможно, строки / константы типов действий не такие, как вы думаете, и что-то не соответствует).

Если эффект не получает отправленное действие, наиболее вероятным объяснением будет то, что store, через который вы отправляете StandardSigninAction, не тот же store, который использует ваш эффект, то есть у вас проблема с DI.

Если это так, вы должны посмотреть, что отличается от других SessionEffects, которые, по вашему мнению, работают. (По крайней мере, у вас есть что-то работающее, и это хорошее место для начала экспериментов.) Они отправляются из другого модуля? Является ли модуль, который отправляет StandardSigninAction, функциональным модулем?

Что произойдет, если вы взломаете один из рабочих SessionEffects, чтобы заменить его отправленное действие на StandardSigninAction? Эффект тогда работает?

Обратите внимание, что вопросы в конце этого ответа не являются вопросами, на которые я хочу получить ответы; это вопросы, которые вам следует задать себе и изучить.

person cartant    schedule 24.03.2017
comment
Привет и большое спасибо, картант. Я принял во внимание совет, который вы любезно предоставили, и думаю, что я нахожусь в отношении возможного решения проблемы ... Я прокомментирую здесь, когда я точно определю и полностью пойму причину проблемы. - person balteo; 26.03.2017
comment
Я борюсь с подобной проблемой - вы можете поделиться своими выводами? Мне нужно отправить действие из избранного модуля и поймать его в эффекте другого избранного модуля. - person Lior Kooznits; 20.02.2018

Поток вашего магазина может останавливаться либо из-за необработанных ошибок, либо - что еще более сбивает с толку - ошибок, которые кажутся «обработанными» с помощью .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 btw, что особенно важно учитывать при трансляции нескольким наблюдателям (например, хранилище ngrx внутренне использует внутренний Subject).

person rob3c    schedule 16.08.2017
comment
Это определенно ответ. Если вы посмотрите на vendor.bundle, вы можете поставить точку останова на ActionSubject.prototype.error и найти ошибку. - person Bryan Rayner; 09.02.2018

Я использую более позднюю версию ngrx (7.4.0), поэтому предложения Картанта:

.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'
person Adam Cox    schedule 06.07.2019
comment
Этот ответ помог мне, так как я пропустил добавление эффектов в EffectsModule.forRoot - person hima; 03.01.2020

Если вы используете версию 8, убедитесь, что вы заключили каждое действие в createEffect.

Пример:

Create$ = createEffect(() => this.actions$.pipe(...))
person Rudi Jansen van Vuuren    schedule 07.11.2019

Другая возможная причина заключается в том, что если вы использовали ng generate для создания модуля, в который вы импортировали эффекты, убедитесь, что он импортирован в модуль приложения, поскольку следующая команда ng generate module myModule не добавит его в модуль приложения.

person Titus Okathe    schedule 03.10.2019