Перейти к содержанию

Reducers

NgRx Reducers являются чистыми функциями и отвечают за смену состояния хранилища в Angular приложении в ответ на возникновение действия, при этом каждый редюсер может изменять только определенную часть состояния.

Изменить состояние в NgRx можно ТОЛЬКО с использованием редюсеров.

users.actions.ts

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

export enum UsersActions {
  LoadUsers = '[Users Page] LoadUsers',
  DeleteUsers = '[Users Page] DeleteUsers',
}

export interface User {
  id: number;
  name: string;
  email: string;
}

export class LoadUsers implements Action {
  readonly type = UsersActions.LoadUsers;

  constructor(public payload: { users: User[] }) {}
}

export class DeleteUsers implements Action {
  readonly type = UsersActions.DeleteUsers;
}

export type UsersUnion = LoadUsers | DeleteUsers;

users.reducer.ts

import {
  UsersUnion,
  UserActions,
} from '../actions/users.actions';

export interface State {
  users: User[];
  count: number;
}

const initialState: State = {
  users: [],
  count: 0,
};

export function usersReducer(
  state: State = initialState,
  action: UsersUnion
) {
  switch (action.type) {
    case UsersActions.LoadUsers:
      return {
        ...state,
        users: action.payload.users,
      };
    case UsersActions.DeleteUsers:
      return {
        ...state,
        users: [],
      };
    default:
      return state;
  }
}

Любое действие, отправляемое в хранилище методом dispatch(), передается всем редюсерам, каждый из которых либо изменяет состояние согласно текущему действию, либо возвращает состояние нетронутым, если обработка такого действия в нем не предусмотрена.

Все изменения состояния хранилища происходят в Angular приложении синхронно, а их порядок зависит от порядка регистрации самих NgRx Reducers.

Редюсер принимает два аргумента:

  • часть текущего состояния, за обработку которого он ответственен;
  • обрабатываемое действие.

Поскольку все NgRx Reducers обрабатывают определенный набор действий и всегда должны возвращать состояние, здесь очень удобно применение оператора switch.

При первом вызове редюсера в качестве значения состояния ему передается undefined, поэтому очень важно определить значение части хранилища по умолчанию, которое задаст необходимую структуру и, если это необходимо, исходные значения свойств этой структуры.

export interface State {
  users: User[];
  count: number;
}

const initialState: State = {
  users: [],
  count: 0,
};

export function usersReducer(
  state: State = initialState,
  action: UsersUnion
) {
  /* ... */
}

Для содержания кода вашего Angular проекта в чистоте и во избежании путаницы, рекомендуется NgRx Reducers и обрабатываемые ими действия хранить в разных файлах. Подробно здесь.

В приложении регистрация NgRx Reducers осуществляется с помощью метода forRoot() модуля StoreModule.

@NgModule({
  imports: [StoreModule.forRoot({users: usersReducer})],
})

Методу должен передаваться объект, ключами которого являются имена частей, формирующих глобальное хранилище, а их значениями - редюсеры, возвращающие значение этих частей хранилища.

Комментарии