Created
January 18, 2023 15:58
-
-
Save kaitwalla/076387e2dc205361d8b29088bfb2eeda to your computer and use it in GitHub Desktop.
NGXS vs. NGRX vs. Elf
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// reports.service.ts | |
import { trackRequestResult } from '@ngneat/elf-requests'; | |
import { setReports } from './reports.repository'; | |
export function fetchReports() { | |
return http.get(reportsUrl).pipe( | |
tap(setReports), | |
trackRequestResult(['reports']) | |
); | |
} | |
// reports.repository.ts | |
import { createStore, withProps } from '@ngneat/elf'; | |
import { select } from '@ngneat/elf'; | |
import { withEntities, withUIEntities, withActiveId } from '@ngneat/elf-entities'; | |
interface Report { | |
id: number, | |
name: string | |
} | |
interface ReportUI { | |
id: number, | |
editMode: boolean | |
} | |
export const reportStore = createStore( | |
{ name: 'reports' }, | |
withEntities<Report>(), | |
withUIEntities<ReportUI>(), | |
withActiveId(), | |
joinRequestResult(['reports']) | |
); | |
export class ReportsRepository { | |
reports$ = reportStore.pipe(select((state) => state.reports)); | |
updateReports(reports: ReportProps['reports']) { | |
reportStore.update((state) => ({ | |
...state, | |
reports | |
})); | |
} | |
} | |
// reports.component.ts | |
import { selectEntity } from '@ngneat/elf-entities'; | |
import { selectActiveEntity } from '@ngneat/elf-entities'; | |
const active$ = reportsStore.pipe(selectActiveEntity()); | |
reportStore.subscribe((state) => { | |
console.log(state); | |
}) | |
// returns observable that calls distinctUntilChanged() | |
const report$ = reportStore.pipe(select((state) => state.reports)); | |
// returns value once without subscribing | |
const state = reportStore.getValue(); | |
const report$ = reportStore.pipe(selectEntity(id)); | |
entities$.subscribe( | |
({ isLoading, isError, isSuccess, data, error, status }) => { | |
console.log( | |
isLoading, | |
isError, | |
isSuccess, | |
status, | |
successfulRequestsCount, | |
data, // typed as Todo[] | |
error | |
); | |
} | |
); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// reports.store.ts | |
import { StoreModule } from '@ngrx/store'; | |
import { EffectsModule } from '@ngrx/effects'; | |
interface ReportsState { | |
reports: Report[]; | |
} | |
// reports.action.ts | |
import { createAction, props } from '@ngrx/store'; | |
export const getReports = createAction('[Reports] Get'); | |
// reports.reducer.ts | |
import { createReducer, on } from '@ngrx/store'; | |
import { getReports, getReportsSuccess, getReportsError } from './reports.actions'; | |
const reportsReducer = createReducer( | |
initialState, | |
on(getReports, state => ({ ...state, loading: true })), | |
on(getReportsSuccess, (state, { reports }) => ({ ...state, loading: false, reports })), | |
on(getReportsError, (state, { error }) => ({ ...state, loading: false, error })) | |
); | |
//reports.effect.ts | |
import { Injectable } from '@angular/core'; | |
import { HttpClient } from '@angular/common/http'; | |
import { Actions, createEffect, ofType } from '@ngrx/effects'; | |
import { of } from 'rxjs'; | |
import { map, catchError, switchMap } from 'rxjs/operators'; | |
import { getReports, getReportsSuccess, getReportsError } from './reports.actions'; | |
@Injectable() | |
export class ReportsEffects { | |
constructor(private actions$: Actions, private http: HttpClient) {} | |
getReports$ = createEffect(() => | |
this.actions$.pipe( | |
ofType(getReports), | |
switchMap(() => | |
this.http.get<Report[]>('https://my-api.com/reports').pipe( | |
map(reports => getReportsSuccess({ reports })), | |
catchError(error => of(getReportsError({ error }))) | |
) | |
) | |
) | |
); | |
} | |
// app.module.ts | |
import { StoreModule } from '@ngrx/store'; | |
import { EffectsModule } from '@ngrx/effects'; | |
import { StoreDevtoolsModule } from '@ngrx/store-devtools'; | |
import { environment } from '../environments/environment'; | |
import { reportsReducer } from './store/reports.reducer'; | |
import { ReportsEffects } from './store/reports.effects'; | |
@NgModule({ | |
imports: [ | |
StoreModule.forRoot({ reports: reportsReducer }), | |
EffectsModule.forRoot([ReportsEffects]), | |
StoreDevtoolsModule.instrument({ maxAge: 25, logOnly: environment.production }) | |
], | |
providers: [ReportsService] | |
}) | |
export class AppModule { } | |
// reports.component.ts | |
import { Component } from '@angular/core'; | |
import { Store } from '@ngrx/store'; | |
import { getReports } from './store/reports.actions'; | |
@Component({ | |
selector: 'app-root', | |
template: ` | |
<div *ngFor="let report of reports$ | async"> | |
{{ report.title }} | |
</div> | |
` | |
}) | |
export class AppComponent { | |
reports$ = this.store.select(state => state.reports); | |
constructor(private store: Store) { | |
this.store.dispatch(getReports()); | |
} | |
} | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// reports.state.ts | |
import { State, Action, StateContext } from '@ngxs/store'; | |
@State<Report[]>({ | |
name: 'reports', | |
defaults: [] | |
}) | |
export class ReportsState { | |
} | |
// reports.service.ts | |
import { Injectable } from '@angular/core'; | |
import { HttpClient } from '@angular/common/http'; | |
@Injectable() | |
export class ReportsService { | |
constructor(private http: HttpClient) {} | |
getReports() { | |
return this.http.get<Report[]>('https://my-api.com/reports'); | |
} | |
} | |
//reports.action.ts | |
import { Get, StateContext } from '@ngxs/store'; | |
import { ReportsService } from './reports.service'; | |
export class GetReports { | |
static readonly type = '[Reports] Get'; | |
} | |
@Injectable() | |
export class ReportsActions { | |
constructor(private reportsService: ReportsService) {} | |
@Get(GetReports) | |
getReports({ patchState }: StateContext<Report[]>) { | |
return this.reportsService.getReports().pipe( | |
tap((reports: Report[]) => { | |
patchState(reports); | |
}) | |
); | |
} | |
} | |
// reports.component.ts | |
import { Component } from '@angular/core'; | |
import { Store } from '@ngxs/store'; | |
import { GetReports } from './reports.actions'; | |
@Component({ | |
selector: 'app-root', | |
template: ` | |
<div *ngFor="let report of reports$ | async"> | |
{{ report.title }} | |
</div> | |
` | |
}) | |
export class AppComponent { | |
reports$ = this.store.select(state => state.reports); | |
constructor(private store: Store) { | |
this.store.dispatch(new GetReports()); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment