NgRx Cheat Sheet
NgRx Core Concepts:
-
Store:
-
The central repository for the application’s state.
-
Maintains a single immutable state tree.
-
-
Actions:
-
Plain objects that describe state changes.
-
Dispatched by components or services to trigger state updates.
-
-
Reducers:
-
Pure functions that specify how the application’s state changes in response to actions.
-
Take the current state and an action and return a new state.
-
-
Selectors:
-
Functions used to derive and select specific pieces of state from the store.
-
Help to prevent unnecessary re-rendering of components.
-
NgRx Store Setup:
import { StoreModule } from '@ngrx/store';
@NgModule({
imports: [
StoreModule.forRoot({ appStateKey: rootReducer }),
],
})
export class AppModule { }
Actions:
import { createAction, props } from '@ngrx/store';
// Define an action
export const increment = createAction('[Counter] Increment');
// Define an action with payload
export const addTodo = createAction('[Todo] Add', props<{ text: string }>());
Reducers:
import { createReducer, on } from '@ngrx/store';
import { increment } from './actions';
export const initialState = 0;
const _counterReducer = createReducer(
initialState,
on(increment, (state) => state + 1)
);
export function counterReducer(state, action) {
return _counterReducer(state, action);
}
Selectors:
import { createSelector } from '@ngrx/store';
const selectFeature = (state) => state.feature;
export const selectFeatureCount = createSelector(
selectFeature,
(state) => state.count
);
Effects:
import { Injectable } from '@angular/core';
import { Actions, createEffect, ofType } from '@ngrx/effects';
import { of } from 'rxjs';
import { catchError, map, mergeMap } from 'rxjs/operators';
import * as fromActions from './actions';
import { SomeService } from './some.service';
@Injectable()
export class SomeEffects {
loadSomething$ = createEffect(() =>
this.actions$.pipe(
ofType(fromActions.loadSomething),
mergeMap(() =>
this.someService.loadSomething().pipe(
map((data) => fromActions.loadSomethingSuccess({ data })),
catchError((error) => of(fromActions.loadSomethingFailure({ error })))
)
)
)
);
constructor(
private actions$: Actions,
private someService: SomeService
) {}
}
Dispatching Actions:
import { Component } from '@angular/core';
import { Store } from '@ngrx/store';
import { increment, addTodo } from './actions';
@Component({
selector: 'app-root',
template: `
<button (click)="increment()">Increment</button>
<button (click)="addTodo()">Add Todo</button>
`,
})
export class AppComponent {
constructor(private store: Store) {}
increment() {
this.store.dispatch(increment());
}
addTodo() {
this.store.dispatch(addTodo({ text: 'New Todo' }));
}
}
State Access in Components:
import { Component } from '@angular/core';
import { Store } from '@ngrx/store';
import { selectFeatureCount } from './selectors';
@Component({
selector: 'app-counter',
template: `
<p>Count: {{ count$ | async }}</p>
`,
})
export class CounterComponent {
count$ = this.store.select(selectFeatureCount);
constructor(private store: Store) {}
}