Эффект 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),
изменить. Вот мой метод SessionSigninService.signin(возвращает возвращаемое значение)
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'));
}
Ответы
Ответ 1
Это не будет окончательный ответ, но, надеюсь, это будет полезно.
Прежде чем начать:
- Убедитесь, что вы используете последние версии пакетов
@ngrx
(которые подходят для используемой версии Angular).
- Если вы обновили какие-либо пакеты, убедитесь, что вы заново запустили среду разработки (то есть перезагрузите узел, сервер и т.д.).
Если вы еще этого не сделали, вы должны взглянуть на реализацию Store
- чтобы вы сделали некоторые образованные догадки о том, что может пойти не так. Заметьте, что Store
довольно светлый. Это как наблюдаемое (использующее состояние как его источник), так и наблюдатель (который подчиняется диспетчеру).
Если вы посмотрите store.dispatch
, вы увидите, что это псевдоним для
store.next
, который вызывает next
на Dispatcher
.
Поэтому вызов:
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
? Выполняется ли эффект?
Обратите внимание, что вопросы в конце этого ответа не являются вопросами, на которые я хочу ответить; это вопросы, которые вы должны задавать себе и исследовать.
Ответ 2
Поток вашего хранилища может останавливаться из-за необработанных ошибок или, возможно, более смутных ошибок, которые, как представляется, обрабатываются с помощью .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 store делает внутреннее использование внутреннего Subject
).
Ответ 3
Я пользуюсь более поздней версией 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'
Ответ 4
Другая возможная причина заключается в том, что если вы использовали ng generate для создания модуля, в который импортировали эффекты, убедитесь, что он импортирован в модуль приложения, поскольку следующая команда "ng generate module myModule" не добавит его в модуль приложения.