NgRx : dispatch one event from a store to another

别说谁变了你拦得住时间么 提交于 2019-12-11 17:49:02

问题


I'm beginning to use @ngrx and I'm facing an issue to which I can't seem to find an answer.

I illustrated it in this stackblitz : when a player picks a race, the specialty should be set back to undefined.

At first I thought I could use the reducer, but it doesn't have knowledge of the store without injection.

How should I approach this issue ?
(Note : this is a reproductible example, I know I can put a second dispatch in my functions. What I want is to do it automatically)

Related code :

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.store.select('race');
  currentSpecialty = this.store.select('specialty');

  constructor(public store: Store<CharacterState>) { }

  dispatchRace(race) {
    this.store.dispatch(new SetRaceAction(race));
  }

  dispatchSpecialty(spec) {
    this.store.dispatch(new SetSpecialtyAction(spec));
  }
}


const SET_RACE = '[RACE] Set';
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 CharacterState {
  readonly race: string;
  readonly specialty: string;
}

回答1:


If you add a console.log in the raceReducer you can see that all the actions are handled by all the reducers :

export function raceReducer(state: string = undefined, action: SetRaceAction): string {
  console.log(action);
  return action.race || state;
}

You just need to handle SetRaceAction and SetSpecialtyAction differently.

Edit of the stackblitz.




回答2:


So if I understand correctly: you want to dispatch one action that triggers another?

  1. this is best done using NGRX effects. Your effects file will listen for the action, and dispatch both when the action is caught. (excuse the snippet, i was having formatting issues)

// make sure to import rxjs 6 correctly
import { map, switchMap, tap } from 'rxjs/operators';

@Effect()
twoActionEvent = this.actions$
    .ofType(appActions.FIRST_ACTION)
    .pipe(
        switchMap((action$: appActions.firstAction) => {
            return //what ever you need in the first action
        }),
        map((firstActionPayload) => {
            return {
               type: appActions.FIRST_ACTION_SUCCESS,
                payload: firstActionPayload
            }
         }),
         tap(() => {
             this.store.dispatch(new appActions.SecondAction(//payload))
         })
     );
constructor(private actions$: Actions,
            private store: Store<AppState>) {}
  1. another way to do this would be to listen for the action in your app, by subscribing to a property in your store, and when that property is true: dispatch the second action



回答3:


I wanted to add one more solution, that I have done in my own implementations when I use flags in my store.

just change the flag in your state during the action you dispatch, for example:

import * as AppActions from './app.actions'; import * as handler from './app.models';

export function appReducer(
        state: handler.AppState = handler.initialAppState,
        action: AppActions.AppActions
    ) {
        switch(action.type) {
            case AppActions.SET_RACE_ACTION:
                return {
                    ...state,
                    race: action.payload
                    // set your flag in state
                    myFlag: undefined
                 }
       }

}



来源:https://stackoverflow.com/questions/52498684/ngrx-dispatch-one-event-from-a-store-to-another

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!