Angular — это мощная платформа для создания масштабируемых и удобных в сопровождении веб-приложений. По мере усложнения приложений управление состоянием становится важнейшим аспектом разработки. NGRX — это библиотека управления состоянием для приложений Angular, которая помогает управлять сложным состоянием приложения и повышает производительность приложения.

В этой статье мы предоставим полное руководство по использованию NGRX с Angular. Мы сосредоточимся на выполнении простых операций CRUD (создание, чтение, обновление, удаление) с использованием NGRX. К концу этого руководства у вас будет четкое представление о том, как реализовать NGRX в приложении Angular и управлять состоянием предсказуемым и эффективным образом.

Оглавление

  1. Что такое NGRX и зачем его использовать?
  2. Настройка проекта Angular
  3. Создание магазина
  4. Определение действий
  5. Реализация редукторов
  6. Создание селекторов
  7. Диспетчерские действия
  8. Отображение данных в компонентах
  9. Обновление данных с помощью действий
  10. Удаление данных с помощью действий
  11. Заключение

1. Что такое NGRX и зачем его использовать?

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

К основным преимуществам использования NGRX относятся:

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

Теперь, когда мы понимаем преимущества использования NGRX, давайте настроим проект Angular и начнем работу с NGRX.

2. Настройка проекта Angular

Прежде чем мы начнем, убедитесь, что в вашей системе установлены Node.js и Angular CLI. Если нет, вы можете установить их, выполнив следующие команды:

npm install -g @angular/cli

Чтобы создать новый проект Angular, используйте интерфейс командной строки Angular для создания стандартного кода:

ng new ngrx-crud-example

Перейдите в только что созданный каталог проекта:

cd ngrx-crud-example

Теперь у нас есть готовый проект Angular, и мы можем приступить к установке необходимых зависимостей для NGRX.

3. Создание магазина

В NGRX хранилище — это место, где осуществляется управление состоянием приложения. Чтобы создать магазин, нам нужно установить пакет @ngrx/store:

npm install @ngrx/store --save

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

Создайте новый файл с именем task.model.ts в каталоге src/app и определите интерфейс Task:

// src/app/task.model.ts

export interface Task {
  id: number;
  title: string;
  description: string;
}

Теперь создайте еще один файл с именем task.reducer.ts в каталоге src/app. Этот файл будет содержать начальное состояние нашего приложения и функцию редуктора, которая обрабатывает изменения состояния:

// src/app/task.reducer.ts

import { Task } from './task.model';

export interface AppState {
  tasks: Task[];
}

export const initialState: AppState = {
  tasks: []
};

export function taskReducer(state = initialState, action): AppState {
  switch (action.type) {
    default:
      return state;
  }
}

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

4. Определение действий

Действия в NGRX используются для описания изменений состояния в приложении. Это простые объекты JavaScript со свойством type, описывающим выполняемое действие. Мы определим три типа действий для нашего приложения управления задачами: AddTask, UpdateTask и DeleteTask.

Создайте новый файл с именем task.actions.ts в каталоге src/app и определите действия:

// src/app/task.actions.ts

import { createAction, props } from '@ngrx/store';
import { Task } from './task.model';

export const addTask = createAction('[Task] Add Task', props<{ task: Task }>());
export const updateTask = createAction('[Task] Update Task', props<{ task: Task }>());
export const deleteTask = createAction('[Task] Delete Task', props<{ id: number }>());

Здесь мы использовали функцию createAction из @ngrx/store для определения наших действий. Первый аргумент createAction — это тип действия, заключенный в квадратные скобки, чтобы указать, что оно относится к функции Task. Второй аргумент, props, используется для определения полезной нагрузки действия. В нашем случае действия addTask и updateTask ожидают объект task, а deleteTask ожидает id в качестве полезной нагрузки.

5. Реализация редукторов

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

Откройте файл task.reducer.ts и импортируйте действия, которые мы определили ранее:

// src/app/task.reducer.ts

import { Task } from './task.model';
import { addTask, updateTask, deleteTask } from './task.actions';

export interface AppState {
  tasks: Task[];
}

export const initialState: AppState = {
  tasks: []
};

export function taskReducer(state = initialState, action): AppState {
  switch (action.type) {
    case addTask.type:
      return { ...state, tasks

: [...state.tasks, action.task] };
    case updateTask.type:
      return {
        ...state,
        tasks: state.tasks.map(task => (task.id === action.task.id ? action.task : task))
      };
    case deleteTask.type:
      return { ...state, tasks: state.tasks.filter(task => task.id !== action.id) };
    default:
      return state;
  }
}

В этом обновленном коде мы импортировали действия и добавили случаи в нашу функцию taskReducer для обработки каждого типа действия. Для addTask мы создаем новое состояние, добавляя новую задачу в массив существующих задач. Для updateTask мы сопоставляем задачи и обновляем одну с подходящим id. По deleteTask отфильтровываем задачу с указанным id.

6. Создание селекторов

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

Создайте новый файл с именем task.selectors.ts в каталоге src/app и определите селекторы:

// src/app/task.selectors.ts

import { createSelector } from '@ngrx/store';
import { AppState } from './task.reducer';

export const selectTasks = (state: AppState) => state.tasks;

export const selectTaskById = (id: number) =>
  createSelector(selectTasks, tasks => tasks.find(task => task.id === id));

В этом фрагменте кода мы использовали функцию createSelector из @ngrx/store для определения наших селекторов. Селектор selectTasks извлекает массив задач из состояния, а selectTaskById принимает аргумент id и возвращает задачу с соответствующим id.

7. Диспетчерские действия

Теперь, когда мы настроили хранилище, определили действия и реализовали редюсеры и селекторы, давайте перейдем к диспетчеризации действий из наших компонентов.

Откройте файл app.component.ts в каталоге src/app. В этом файле мы будем отправлять действия для добавления, обновления и удаления задач.

// src/app/app.component.ts

import { Component } from '@angular/core';
import { Store } from '@ngrx/store';
import { AppState } from './task.reducer';
import { addTask, updateTask, deleteTask } from './task.actions';
import { Task } from './task.model';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent {
  tasks: Task[] = [];

  constructor(private store: Store<AppState>) {
    this.store.select('tasks').subscribe(tasks => this.tasks = tasks);
  }

  addNewTask() {
    const newTask: Task = {
      id: this.tasks.length + 1,
      title: 'New Task',
      description: 'This is a new task.'
    };
    this.store.dispatch(addTask({ task: newTask }));
  }

  updateTask(task: Task) {
    const updatedTask: Task = { ...task, title: 'Updated Task', description: 'This task has been updated.' };
    this.store.dispatch(updateTask({ task: updatedTask }));
  }

  deleteTask(id: number) {
    this.store.dispatch(deleteTask({ id }));
  }
}

В этом фрагменте кода мы импортировали необходимые модули и зависимости, включая Store из @ngrx/store, наши действия и интерфейс Task. Мы также определили методы для добавления, обновления и удаления задач и отправили соответствующие действия с помощью метода store.dispatch().

8. Отображение данных в компонентах

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

Откройте файл app.component.html в каталоге src/app и обновите его следующим образом:

<!-- src/app/app.component.html -->

<div *ngFor="let task of tasks" class="task">
  <h3>{{ task.title }}</h3>
  <p>{{ task.description }}</p>
  <button (click)="updateTask(task)">Update</button>
  <button (click)="deleteTask(task.id)">Delete</button>
</div>
<button (click)="addNewTask()">Add New Task</button>

В этом HTML-шаблоне мы используем директиву Angular *ngFor для циклического перебора задач и отображения их заголовков и описаний. Мы также добавляем кнопки для обновления и удаления каждой задачи и кнопку для добавления новой задачи.

9. Обновление данных с помощью действий

При нажатии кнопки «Обновить» для задачи вызывается метод updateTask(), который отправляет действие updateTask с обновленным объектом задачи.

10. Удаление данных с помощью действий

Когда для задачи нажимается кнопка «Удалить», вызывается метод deleteTask(), который отправляет действие deleteTask с id задачи.

11. Заключение

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

NGRX предоставляет надежное и масштабируемое решение для управления состоянием приложений, особенно полезное для больших и сложных приложений. Используя NGRX, вы можете сделать свои приложения Angular более удобными в сопровождении, предсказуемыми и эффективными.

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