Как работает ngrx


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

В основе NgRx лежит концепция однонаправленного потока данных. Сначала состояние инициализируется, а затем может быть изменено только с помощью действий, которые представляют собой простые объекты с определенными свойствами. Действия отправляются в централизованный хранилище, а затем проходят через редукторы, которые объединяют текущее состояние с действием и возвращают новое состояние.

NgRx также предоставляет возможность использования селекторов для получения данных из состояния. Селекторы — это функции, которые принимают текущее состояние и возвращают выбранные данные. Они позволяют избежать прямого доступа к состоянию и позволяют управлять данными более гибко и эффективно.

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

Основные понятия ngrx

Основными понятиями, с которыми придется столкнуться при работе с ngrx, являются:

  • Actions: действия представляют собой объекты, которые описывают события, происходящие в приложении. Они передают информацию о действии и используются для вызова соответствующих редукторов.
  • Reducers: редукторы — это функции, которые принимают текущее состояние и действие, и возвращают новое состояние приложения. Они отвечают за обновление состояния, основываясь на переданных действиях.
  • Store: хранилище — это объект, который содержит всю информацию о состоянии приложения. Он предоставляет интерфейс для чтения и записи данных приложения.
  • Selectors: селекторы — это функции, которые используются для извлечения определенных кусков данных из состояния приложения. Они позволяют получить только нужные данные, минимизируя количество кода и упрощая разработку.
  • Effects: эффекты — это функции, которые позволяют обрабатывать побочные эффекты, такие как асинхронные вызовы к API или изменение маршрута. Они могут быть использованы для вызова действий, обновления состояния приложения и других побочных эффектов.

Эти основные понятия формируют основу для работы с ngrx и обеспечивают единообразие, предсказуемость и управляемость состояния в Angular приложениях.

Преимущества использования ngrx

Использование библиотеки ngrx для управления состоянием в Angular-приложениях имеет множество преимуществ. Вот некоторые из них:

1.Централизованное хранение состояния.Состояние приложения хранится в едином объекте, который можно легко отслеживать и изменять с помощью однонаправленного потока данных.
2.Упрощение логики приложения.Благодаря использованию глобального хранилища состояния, логика приложения становится проще и более предсказуемой. Компоненты становятся малозависимыми и могут сосредоточиться на отображении данных.
3.Легкая отладка и поддержка.С использованием инструментов разработчика можно легко отслеживать изменения состояния и понимать, какие действия вызывают эти изменения. Это существенно упрощает отладку и поддержку приложения.
4.Возможность переиспользования состояния.Хранение состояния в отдельном хранилище позволяет переиспользовать его между различными компонентами и даже между различными Angular-приложениями.
5.Улучшение производительности.Благодаря использованию иммутабельности и упрощению логики обновления состояния, ngrx способствует более эффективной работе с данными и повышает производительность приложения.

Использование ngrx для управления состоянием в Angular-приложениях позволяет создавать более масштабируемые, надежные и легко поддерживаемые приложения.

Шаблон проектирования в ngrx

Состояние представляет собой единственный объект, который содержит всю информацию о приложении. В NgRx состояние хранится в структурированном виде, подобно базе данных. Каждый кусочек данных должен быть легко доступным и изменяемым.

Действия представляют собой события, которые указывают, что произошло изменение состояния. Они описывают, какую операцию нужно выполнить с состоянием. Действия в NgRx являются неизменяемыми и имеют тип и данные, связанные с соответствующим действием.

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

Шаблон проектирования в NgRx гарантирует, что изменения состояния происходят только через действия и редукторы. Действия служат механизмом чтения, а редукторы — механизмом записи состояния. Это обеспечивает предсказуемость и контроль в приложении, позволяя отслеживать, что происходит внутри, и легко отменять или повторять изменения.

Шаблон проектирования в NgRx также позволяет использовать селекторы для получения данных из состояния. Селекторы — это функции, которые принимают состояние в качестве аргумента и возвращают определенную информацию. Они позволяют избежать ненужных перерисовок и упрощают получение данных из состояния.

Использование шаблона проектирования в NgRx позволяет создавать масштабируемые и легко тестируемые приложения. Он помогает упростить управление состоянием и обеспечивает однозначность взаимодействия с состоянием в Angular-приложении.

Централизованное хранение состояния

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

Основная идея централизованного хранения состоит в том, чтобы иметь одну единственную истину (состояние), к которой можно обратиться из любого компонента приложения. Это позволяет упростить код и сделать его более предсказуемым.

Для работы с централизованным хранилищем ngrx предлагает использовать следующие концепции:

КонцепцияОписание
ActionsДействия, которые могут происходить в системе. Они представляют собой простые объекты, содержащие информацию о произошедшем событии.
ReducersФункции, которые обрабатывают действия и обновляют состояние хранилища. Они принимают текущее состояние и действие, а затем возвращают новое состояние.
SelectorsФункции, которые позволяют получать нужные данные из состояния хранилища. Они предоставляют удобный способ извлечения и трансформации данных для компонентов приложения.

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

Централизованное хранение состояния является одним из ключевых преимуществ использования ngrx. Это позволяет легко отслеживать и контролировать изменения в приложении, а также упрощает разработку и поддержку кода.

Действия и редукторы

Действия в ngrx представляются в виде классов, обычно называемых «действием», которые реализуют интерфейс Action. Этот интерфейс определяет обязательное свойство type — строку, которая описывает тип действия. Кроме того, действия могут содержать дополнительные свойства, которые описывают данные, передаваемые с действием.

Редукторы в ngrx — это функции, которые принимают два параметра: текущее состояние и действие. Они должны быть чистыми функциями, то есть не иметь побочных эффектов и всегда возвращать новый объект состояния, а не изменять его напрямую. Редукторы обычно используют оператор switch для проверки типа действия и определения, какое изменение состояния необходимо выполнить.

Все действия, определенные для приложения, должны быть перечислены в структуре состояния, которая называется «стор». Рекомендуется использовать отдельный файл для определения действий. Затем действия экспортируются и могут быть импортированы в редукторы и компоненты приложения.

Пример использования действий и редукторов:

ДействиеРедуктор
LoadDataActionloadDataReducer
AddItemActionaddItemReducer
DeleteItemActiondeleteItemReducer

В приведенном примере LoadDataAction, AddItemAction и DeleteItemAction — это классы действий, которые определены в отдельных файлах. При выполнении действий соответствующие редукторы будут вызваны с текущим состоянием и переданным действием. Редукторы могут изменять состояние приложения и возвращать новое состояние.

Использование действий и редукторов позволяет создавать предсказуемое и масштабируемое управление состоянием в приложении ngrx. Действия определяют, какие изменения должны быть выполнены, а редукторы обрабатывают эти изменения и возвращают новое состояние. Это позволяет создавать составные действия и иметь полный контроль над изменениями в приложении.

Эффекты и селекторы

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

Селекторы, в свою очередь, используются для выборки данных из глобального состояния приложения. Они позволяют организовать доступ к данным из разных компонентов, необходимых для их отображения или использования.

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

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

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

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

При разработке приложения с использованием ngrx рекомендуется активно использовать эффекты и селекторы для управления состоянием и доступа к данным.

Пример применения ngrx в приложении

Для наглядной иллюстрации работы библиотеки ngrx, рассмотрим пример применения ее основных концепций в приложении для управления списком задач.

1. Создание стора:

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

store.module.ts

import { NgModule } from '@angular/core';import { StoreModule } from '@ngrx/store';import { reducers } from './reducers';@NgModule({imports: [StoreModule.forRoot(reducers)]})export class AppStoreModule {}

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

Затем мы создаем редьюсеры, которые будут обрабатывать действия и обновлять состояние стора. В этом примере, у нас есть два редьюсера: один для обработки действий связанных с задачами, и другой для обработки действия связанного с выбранным фильтром.

reducers.ts

import { ActionReducerMap } from '@ngrx/store';import { taskReducer } from './task.reducer';import { filterReducer } from './filter.reducer';export interface AppState {tasks: Array<string>;filter: string;}export const reducers: ActionReducerMap<AppState> = {tasks: taskReducer,filter: filterReducer};

3. Создание действий:

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

actions.ts

import { createAction, props } from '@ngrx/store';export const addTask = createAction('[Task] Add Task',props<{ task: string }>());export const deleteTask = createAction('[Task] Delete Task',props<{ task: string }>());export const changeFilter = createAction('[Filter] Change Filter',props<{ filter: string }>());

4. Создание компонента:

Затем мы создаем компонент, который будет использовать стор для получения и отображения задач и текущего выбранного фильтра. Компонент также должен быть подписан на изменения состояния стора, чтобы обновлять отображение при изменении состояния.

task-list.component.ts

import { Component, OnInit } from '@angular/core';import { Store, select } from '@ngrx/store';import { Observable } from 'rxjs';import { AppState } from './reducers';import { selectTasks, selectFilter } from './selectors';@Component({selector: 'app-task-list',template: `<ul><li *ngFor="let task of tasks$ | async">{{ task }}</li></ul><p>Selected Filter:  async }</p>`})export class TaskListComponent implements OnInit {tasks$: Observable<Array<string>>;filter$: Observable<string>;constructor(private store: Store<AppState>) {}ngOnInit() {this.tasks$ = this.store.pipe(select(selectTasks));this.filter$ = this.store.pipe(select(selectFilter));}}

5. Использование действий и редьюсеров:

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

task-list.component.ts

import { Component } from '@angular/core';import { Store } from '@ngrx/store';import { addTask, deleteTask, changeFilter } from './actions';@Component({selector: 'app-task-list',template: `<input [(ngModel)]="newTask" placeholder="New Task" /><button (click)="onAddTask()">Add Task</button><button (click)="onDeleteTask(task)">Delete Task</button><button (click)="onChangeFilter(filter)">Change Filter</button>`})export class TaskListComponent {newTask = '';taskToDelete = '';filterToChange = '';constructor(private store: Store<AppState>) {}onAddTask() {this.store.dispatch(addTask({ task: this.newTask }));this.newTask = '';}onDeleteTask(task: string) {this.store.dispatch(deleteTask({ task: task }));}onChangeFilter(filter: string) {this.store.dispatch(changeFilter({ filter: filter }));}}

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

Обратите внимание, что данный пример был упрощен для наглядности и не содержит полного кода приложения.

Настройка ngrx в проекте

Для использования библиотеки ngrx в вашем проекте необходимо выполнить несколько шагов настройки:

1. Установите необходимые зависимости:

npm install @ngrx/storenpm install @ngrx/effectsnpm install @ngrx/entitynpm install @ngrx/store-devtools

2. Создайте папку «state» в корне вашего проекта. В этой папке будут храниться все файлы, связанные с состоянием приложения.

3. Создайте файл «app.reducer.ts» в папке «state». В этом файле будут объявлены и скомбинированы все редюсеры вашего приложения. Например:

import { combineReducers } from '@ngrx/store';import { reducer as counterReducer } from './counter/counter.reducer';import { reducer as todosReducer } from './todos/todos.reducer';import { reducer as userReducer } from './user/user.reducer';export const rootReducer = combineReducers({  counter: counterReducer,  todos: todosReducer,  user: userReducer});

4. Создайте файлы для каждого редюсера, например «counter.reducer.ts», «todos.reducer.ts», «user.reducer.ts», в папке «state». Реализуйте логику каждого редюсера в соответствии с требованиями вашего приложения.

5. Создайте файл «app.actions.ts» в папке «state». В этом файле будут объявлены все действия, которые могут производиться в вашем приложении. Например:

import { createAction, props } from '@ngrx/store';export const increment = createAction('[Counter] Increment');export const decrement = createAction('[Counter] Decrement');export const addTodo = createAction('[Todos] Add Todo', props<{ title: string }>());export const removeTodo = createAction('[Todos] Remove Todo', props<{ id: string }>());export const setUser = createAction('[User] Set User', props<{ user: User }>());

6. Создайте файл «app.effects.ts» в папке «state». В этом файле будут объявлены все эффекты, которые могут быть связаны с вашими действиями. Например:

import { Injectable } from '@angular/core';import { Actions, createEffect, ofType } from '@ngrx/effects';import { map, mergeMap } from 'rxjs/operators';import { UserService } from '../services/user.service';import { setUser } from './app.actions';@Injectable()export class AppEffects {  setUser$ = createEffect(() => {    return this.actions$.pipe(      ofType('[User] Load User'),      mergeMap(() =>        this.userService.getUser().pipe(          map(user => setUser({ user }))      )  });}

7. Импортируйте и добавьте в список импортов все редюсеры, эффекты и действия в файле «app.module.ts»:

import { StoreModule } from '@ngrx/store';import { EffectsModule } from '@ngrx/effects';import { rootReducer } from './state/app.reducer';import { AppEffects } from './state/app.effects';import { appReducer } from './state/app.reducer';@NgModule({  imports: [    StoreModule.forRoot(appReducer),    EffectsModule.forRoot([AppEffects])  ]})export class AppModule { }

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

Добавить комментарий

Вам также может понравиться