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.

Relaterede artikler