В архитектуре Angular приложения для управления состоянием часто
используется паттерн Redux, реализованный через
библиотеку @ngrx/store. Основные концепции включают
Actions, Reducers и
Store.
Action — это объект, описывающий изменение состояния. Объект содержит тип действия и необязательный payload с данными.
Пример определения action:
import { createAction, props } from '@ngrx/store';
export const addTodo = createAction(
'[Todo List] Add Todo',
props<{ title: string }>()
);
export const removeTodo = createAction(
'[Todo List] Remove Todo',
props<{ id: number }>()
);
[Todo List] для
удобства отладки.props задаёт структуру данных, передаваемых в
action.Reducer — чистая функция, которая принимает текущее состояние и action и возвращает новое состояние.
Пример reducer для списка задач:
import { createReducer, on } from '@ngrx/store';
import { addTodo, removeTodo } from './todo.actions';
export interface TodoState {
todos: { id: number; title: string }[];
}
export const initialState: TodoState = {
todos: []
};
export const todoReducer = createReducer(
initialState,
on(addTodo, (state, { title }) => ({
...state,
todos: [...state.todos, { id: state.todos.length + 1, title }]
})),
on(removeTodo, (state, { id }) => ({
...state,
todos: state.todos.filter(todo => todo.id !== id)
}))
);
Store — централизованное хранилище состояния приложения. Через него компоненты получают доступ к состоянию и могут отправлять actions для его изменения.
Регистрация store в модуле:
import { StoreModule } from '@ngrx/store';
import { todoReducer } from './todo.reducer';
@NgModule({
imports: [
StoreModule.forRoot({ todos: todoReducer })
]
})
export class AppModule {}
Использование store в компоненте:
import { Store } from '@ngrx/store';
import { Observable } from 'rxjs';
import { addTodo } from './todo.actions';
@Component({
selector: 'app-todo',
template: `
<ul>
<li *ngFor="let todo of todos$ | async">{{ todo.title }}</li>
</ul>
<button (click)="addNewTodo()">Add Todo</button>
`
})
export class TodoComponent {
todos$: Observable<{ id: number; title: string }[]>;
constructor(private store: Store<{ todos: { id: number; title: string }[] }>) {
this.todos$ = store.select('todos');
}
addNewTodo() {
this.store.dispatch(addTodo({ title: 'New Task' }));
}
}
Store обеспечивает предсказуемость состояния, упрощает отладку и масштабирование приложения. Actions задают намерения, Reducers обрабатывают эти намерения, а Store хранит актуальное состояние.