Проблема может быть повторно вызвана в этот stackblitz.
Пример прост: пользователь выбирает расу и специальность.
Я хочу, чтобы при выборе расы специальность сбрасывалась (ред?).
Для этого я создал эффект:
@Effect()
raceChange = this.actions
.pipe(
ofType(SET_RACE),
mapTo(new SetSpecialtyAction(''))
);
Но действие не добавляется в поток. Может кто-нибудь объяснить мне, почему? (Я новичок в @ngrx, поэтому будьте внимательны!)
PS: Я знаю, что могу использовать решение из моего предыдущего вопроса, но я пытаюсь изучить основы ngrx.
код для компонента stackblitz:
import { Component } from '@angular/core';
import { Store, Action, ActionReducerMap } from '@ngrx/store';
@Component({
selector: 'my-app',
template:
`
<select #race (change) = "dispatchRace(race.value)" placeholder = "Select a race">
<option value = "Elf">Elf</option>
<option value = "Orc">Orc</option>
<option value = "Dwarf">Dwarf</option>
</select>
<select #spec (change) = "dispatchSpecialty(spec.value)" placeholder = "Select a specialty">
<option value = "Warrior">Warrior</option>
<option value = "Berzerkrer">Berzerkrer</option>
<option value = "Healer">Healer</option>
</select>
<p>
Current race: {{ (currentRace | async) || 'None' }}
</p>
<p>
Current Spec: {{ (currentSpecialty | async) || 'None' }}
</p>
`
})
export class AppComponent {
currentRace = this.raceStore.select('race');
currentSpecialty = this.specStore.select('specialty');
constructor(
public raceStore: Store<RaceState>,
public specStore: Store<SpecialtyState>,
) {
this.currentRace.subscribe(x => console.info('race : ', x));
this.currentSpecialty.subscribe(x => console.info('spec : ', x))
}
dispatchRace(race) {
this.raceStore.dispatch(new SetRaceAction(race));
}
dispatchSpecialty(spec) {
this.specStore.dispatch(new SetSpecialtyAction(spec));
}
}
export const SET_RACE = '[RACE] Set';
export const SET_SPECIALTY = '[CLASS] Set';
export class SetRaceAction implements Action {
readonly type = SET_RACE;
constructor(public race: string) { }
}
export class SetSpecialtyAction implements Action {
readonly type = SET_SPECIALTY;
constructor(public specialty: string) { }
}
export function raceReducer(state: string = undefined, action: SetRaceAction): string {
return action.race || state;
}
export function specialtyReducer(state: string = undefined, action: SetSpecialtyAction): string {
return action.specialty || state;
}
export interface RaceState {
readonly race: string;
}
export interface SpecialtyState {
readonly specialty: string;
}





mapTo отображает излучение в строку, используя map, чтобы отобразить действие, которое будет отправлено.
Чтобы ваш пример работал, я изменил две вещи:
1- замените mapTo на map в эффекте:
@Effect()
raceChange = this.actions
.pipe(
ofType(SET_RACE),
map(() => new SetSpecialtyAction(''))
);
2- Измените редуктор, который игнорировал пустые значения:
export function specialtyReducer(state: string = undefined, action: SetSpecialtyAction): string {
return action.specialty;
}
const value = '' || 'Not Empty';
console.info(value);Вы также можете сопоставить несколько действий, используя switchMap и возвращая массив fo actions:
@Effect()
raceChange = this.actions
.pipe(
ofType(SET_RACE),
switchMap(() => [new SetSpecialtyAction(''), ...])
);
Технически у вас может быть фильтр в конвейере эффектов RxJs, чтобы предотвратить бесконечный цикл. Но я бы избегал эффектов, которые могут запускать друг друга.
Нет необходимости в эффекте, вы можете прослушивать гонку внутри специального редуктора:
export function specialtyReducer(state: string = undefined, action: SetSpecialtyAction | SetRaceAction): string {
switch(action.type) {
case SET_RACE:
return '';
default:
return action.specialty || state;
}
}
Я сказал, что это именно то, что я уже использую, и я не хочу использовать, потому что я изучаю эффекты.
Я хочу немного защитить свой ответ здесь, потому что вы этого не сказали и не используете решение, которое я написал здесь. Если вы хотите изучить эффекты, вы также должны знать, когда использовать эффекты, а когда нет. Этот случай на самом деле не «вызывает» побочный эффект, а просто изменяет состояние, что делает его подходящим для использования редукторов. Кроме того, принятый ответ может вызвать проблемы позже, когда вы введете дополнительные действия, потому что редуктор всегда будет очищать состояние, когда в действии нет specialty.
Это минимальный воспроизводимый пример, а не реальный случай. Я пытаюсь понять, как работают эффекты и что они делают. Благодаря принятому ответу, теперь верю. Я неявно сказал, что использую это решение, которое связано в моем вопросе, которое вы, по-видимому, вообще не читали. Ваш ответ хорош, не поймите меня неправильно, я ничего не имею против: моя проблема в том, что вы полностью проигнорировали контекст вопроса и фактически создали дубликат. Этот вопрос касался того, что эффекты не работают (потому что я сделал что-то глупое), а не о том, какое решение лучше всего использовать.
: thumbsup: Наверное, я неправильно понял твой вопрос.
Черт побери, я совсем забыл, что игнорирую пустые значения! Одно это решило мою проблему. Принимаю во внимание ваши замечания по поводу
mapToиswitchMap, спасибо! Быстрый вопрос, если вы знаете, как: учитывая, что у меня есть два действия, как я могу испуститьSetRaceActionв своем эффекте без запуска бесконечного цикла? Нужно ли мне для этого создавать новое состояние?