angular
July 31

Использование Flux-паттерна в Angular

Flux — это архитектурный паттерн, используемый для создания одностороннего потока данных в приложениях. Он был разработан Facebook и используется для управления состоянием в приложениях, особенно когда они становятся сложными. В Angular для работы со стором можно использовать Flux-подобные библиотеки, такие как NgRx.

Основные концепции Flux

  1. Store: Хранит состояние приложения и логику управления этим состоянием. В Angular это может быть реализовано с помощью NgRx Store, который представляет собой реактивное хранилище для управления состоянием приложения.
  2. Actions: Объекты, которые описывают изменения в состоянии. Actions отправляются в стор для инициирования изменений состояния.
  3. Dispatcher: Центральный узел, который принимает actions и распределяет их в сторы. В NgRx это представлено метками действия, которые передаются в редукторы.
  4. Reducers: Чистые функции, которые принимают текущее состояние и action, затем возвращают новое состояние. В NgRx редукторы определяют, как изменяется состояние в ответ на actions.
  5. Selectors: Функции для получения данных из store. Они помогают избежать прямого доступа к состоянию и способствуют созданию более модульного кода.

Пример использования Flux-подхода с NgRx в Angular

1. Установка NgRx

Для начала необходимо установить необходимые пакеты NgRx:

npm install @ngrx/store @ngrx/effects @ngrx/store-devtools

2. Определение Actions

Создайте файл actions.ts для определения действий:

codeimport { createAction, props } from '@ngrx/store';

export const addTodo = createAction('[Todo List] Add Todo', props<{ todo: string }>());
export const removeTodo = createAction('[Todo List] Remove Todo', props<{ index: number }>());

3. Создание Reducers

Создайте файл reducers.ts для определения редукторов:

import { createReducer, on } from '@ngrx/store';
import { addTodo, removeTodo } from './actions';

export const initialState: string[] = [];

const _todoReducer = createReducer(
  initialState,
  on(addTodo, (state, { todo }) => [...state, todo]),
  on(removeTodo, (state, { index }) => state.filter((_, i) => i !== index))
);

export function todoReducer(state: any, action: any) {
  return _todoReducer(state, action);
}

4. Регистрация Store в модуле

Добавьте стор в корневой модуль app.module.ts:

import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { StoreModule } from '@ngrx/store';
import { todoReducer } from './reducers';

import { AppComponent } from './app.component';

@NgModule({
  declarations: [
    AppComponent
  ],
  imports: [
    BrowserModule,
    StoreModule.forRoot({ todos: todoReducer })
  ],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule { }

5. Использование Store в компоненте

Теперь вы можете использовать стор в компоненте:

import { Component } from '@angular/core';
import { Store } from '@ngrx/store';
import { Observable } from 'rxjs';
import { addTodo, removeTodo } from './actions';

interface AppState {
  todos: string[];
}

@Component({
  selector: 'app-root',
  template: `
    <div>
      <h1>Todo List</h1>
      <input #todoInput>
      <button (click)="add(todoInput.value); todoInput.value=''">Add Todo</button>
      <ul>
        <li *ngFor="let todo of todos$ | async; let i = index">
          {{ todo }}
          <button (click)="remove(i)">Remove</button>
        </li>
      </ul>
    </div>
  `
})
export class AppComponent {
  todos$: Observable<string[]>;

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

  add(todo: string) {
    this.store.dispatch(addTodo({ todo }));
  }

  remove(index: number) {
    this.store.dispatch(removeTodo({ index }));
  }
}