javascript - En bedste praksis for ngrx/redux handlingskontekst
Jeg prøver at finde bedste praksis for dette scenarie, men jeg kan ikke finde det.
problem: Jeg ønsker ikke at gentage actions-filer, som i mit eksempel home-todos.actions og sport-todos-actions, jeg vil bruge den samme to-dos.action-fil. og den samme reducer.
eksempel: Jeg skriver en todo-applikation, for eksempel, i dette eksempel kan du se problemet, hvis jeg udsender en handling med typen 'ADD_TODO_ASYNC', vil den blive udsendt i home (effekter og reducer) og sport (effekter og reducer)
todos.handlinger.ts
const ADD_TODO_ASYNC = 'ADD TODO ASYNC';
const ADD_TODO_COMPLETE = 'ADD TODO COMPLETE';
const ADD_TODO_FAILD = 'AD TODO FAILD';
class addTodoComplete {
type = ADD_TODO_COMPLETE;
}
class addTodoFaild {
type = ADD_TODO_COMPLETE;
}
export type Actions = addTodoComplete | addTodoFaild;
sport.effects.ts
@Injectable()
export class SportTodosService {
@Effect() ADD_TODO_ASYNC$ = this.actions$.ofType(TodosActionTypes.ADD_TODO_ASYNC)
.map(toPayload)
.swithMap( (todo: Todo) => this.api.addTodo(todo))
.map((todo: Todo) => TodosActionTypes.addTodoComplete(todo))
constructor(
private actions$: Actions,
private api: api
) { }
}
home.effects.ts
export class HomeTodosService {
@Effect() ADD_TODO_ASYNC$ = this.actions$.ofType(TodosActionTypes.ADD_TODO_ASYNC)
...
constructor(
...
) { }
}
reducer
function todosReducer(state, action: TodosActionTypes.Actions) {
switch (action.type) {
case TodosActionTypes.ADD_TODO_COMPLETE:
return state;
default:
return state;
}
}
app.module.ts
@NgModule({
declarations: [
AppComponent
],
imports: [
StoreModule.forRoot({
sport: todosReducer,
home: todosReducer,
}),
EffectsModule.forRoot([
SportTodosService
HomeTodosService,
])
],
providers: [
api
],
bootstrap: [AppComponent]
})
export class AppModule { }
Jeg prøver at forstå, hvad der er den bedste praksis for dette scenarie? Skal man skrive handlinger med kontekst som 'HOME_ADD_TODO' og 'SPORT_ADD_TODO'?
eller have en officiel måde?
hvis du kender løsningen, er det ligegyldigt om løsningen er til redux eller ngrx
tak alle
Svar #1
For at forstå dette problem, skal du tænke igen over din app-arkitektur. Generelt er genanvendelige reducer/actions forkert.
hvorfor er det forkert? i det nuværende synspunkt virker det fantastisk at skrive genanvendelige reducer og handlinger, mindre boilerplate, og ikke "DRY". i eksemplet på din app er 'ADD_TO_DO' for hjem og sport ens.
men i fremtiden vil det være farligt, at tænke, at din chef/kunder har brug for fremtid i sport add_to_do. Hvis du ændrer logikken i den genanvendelige reducer, vil din app gå i stykker. (du kan begynde at rette din genanvendelige reducer med if-sætninger for at få det til at virke, men hvis din app vokser, vil det ikke være fleksibelt/læsbart/vedligeholdelsesvenligt).
så ja, det ser ud til, at du skal skrive 2 reducers i dette tilfælde, og 2 actions-filer. I øjeblikket vil det føles ens, men i fremtiden vil det være en fordel og fleksibelt.
held og lykke!
Svar #2
Her er et link med nogle af mønstrene og praksisserne for ngrx.
Det er meningen, at det skal fungere på den måde, du har beskrevet. this.actions$ er en Observable, så den vil udsende, uanset hvor du bruger den. Da TodosActionTypes.ADD_TODO_ASYNC er den samme type i både home.effects.ts og sport.effects.ts, vil den udsende begge steder.
Jeg er ikke sikker på, at du kan undgå at have separate handlinger i dit tilfælde, men du kan reducere mængden af standardkode.
Jeg ville prøve noget i denne stil:
todos.handlinger.ts
abstract class addTodoComplete{
constructor(readonly type: string){
//rest of the behavior
}
}
abstract class addTodoFailed{
constructor(readonly type: string){
//rest of the behavior
}
}
todos.sport-handlinger.ts
const ADD_TODO = "[Sport] Add Todo";
const ADD_TODO_FAILED = "[Sport] Add Todo Failed";
class sportsAddTodoComplete extends addTodoComplete{
constructor(){
super(ADD_TODO);
//rest of the behavior
}
}
class sportsAddTodoFailed extends addTodoFailed{
constructor(){
super(ADD_TODO_FAILED);
//rest of the behavior
}
}
Det samme gælder for hjemmeversionen.
Derudover ville du sandsynligvis have separate SportTodosActionTypes og HomeTodosActionTypes.
Du vil ikke kunne redde dig helt fra "copy-paste", men det bør hjælpe til en vis grad.
REDIGER:
Hvad angår reducers, er det sandt, at du med denne tilgang vil skulle skrive to reducers, men det behøver ikke at være et "copy-paste" arbejde
sport.reducer.ts
import { todoReducer } from './reducer';
export function sportsTodoReducer(state, action: SportTodoActionTypes.Actions){
todoReducer(state, action);
}
Det samme gælder for home-versionen.
