NgRx: установка и конфигурация

NgRx — библиотека управления состоянием в Angular на основе паттерна Redux. Она позволяет централизованно хранить состояние приложения, упрощает обработку событий и делает код предсказуемым.

Установка NgRx

  1. Установка основных пакетов:
ng add @ngrx/store
ng add @ngrx/effects
ng add @ngrx/store-devtools
ng add @ngrx/entity
ng add @ngrx/router-store
  • @ngrx/store — основной модуль для хранения состояния.
  • @ngrx/effects — управление побочными эффектами (например, HTTP-запросы).
  • @ngrx/store-devtools — интеграция с инструментами разработки Redux DevTools.
  • @ngrx/entity — удобная работа с коллекциями сущностей.
  • @ngrx/router-store — синхронизация маршрутов с состоянием приложения.

Базовая конфигурация Store

Создание корневого состояния:

export interface AppState {
  counter: number;
}

export const initialState: AppState = {
  counter: 0
};

Создание редьюсера:

import { createReducer, on } from '@ngrx/store';
import { increment, decrement } from './counter.actions';

export const counterReducer = createReducer(
  initialState,
  on(increment, state => ({ ...state, counter: state.counter + 1 })),
  on(decrement, state => ({ ...state, counter: state.counter - 1 }))
);

Регистрация редьюсера в модуле приложения:

import { StoreModule } from '@ngrx/store';
import { counterReducer } from './counter.reducer';

@NgModule({
  imports: [
    BrowserModule,
    StoreModule.forRoot({ counter: counterReducer })
  ]
})
export class AppModule {}

Создание действий (Actions)

import { createAction } from '@ngrx/store';

export const increment = createAction('[Counter] Increment');
export const decrement = createAction('[Counter] Decrement');

Эффекты (Effects)

Эффекты позволяют обрабатывать асинхронные операции:

import { Injectable } from '@angular/core';
import { Actions, createEffect, ofType } from '@ngrx/effects';
import { EMPTY } from 'rxjs';
import { map, mergeMap, catchError } from 'rxjs/operators';
import { DataService } from './data.service';
import * as DataActions from './data.actions';

@Injectable()
export class DataEffects {
  loadData$ = createEffect(() =>
    this.actions$.pipe(
      ofType(DataActions.loadData),
      mergeMap(() => this.dataService.getAll()
        .pipe(
          map(data => DataActions.loadDataSuccess({ data })),
          catchError(() => EMPTY)
        ))
    )
  );

  constructor(
    private actions$: Actions,
    private dataService: DataService
  ) {}
}

Интеграция DevTools

import { StoreDevtoolsModule } from '@ngrx/store-devtools';
import { environment } from '../environments/environment';

@NgModule({
  imports: [
    StoreDevtoolsModule.instrument({ maxAge: 25, logOnly: environment.production })
  ]
})
export class AppModule {}

Рекомендации по конфигурации

  • Использовать feature modules для разделения состояния на логические части.
  • Эффекты следует размещать отдельно от редьюсеров для лучшей масштабируемости.
  • Для коллекций сущностей использовать @ngrx/entity — это упрощает CRUD-операции.
  • Включение DevTools только в development mode, чтобы не перегружать продакшн.

Эта конфигурация создаёт устойчивую основу для масштабируемого Angular-приложения с централизованным управлением состоянием.