Redux 模式是管理 Web 应用程序状态的一种非常强大的方法,尤其是在应用程序变得更加复杂时。 Redux 库最常与 React 一起使用,但由于 ngrx/store 库,结合 RxJS 的强大功能,我们可以在 Angular 应用程序中以类似 Redux 的方式管理应用程序的状态。
这里快速回顾一下 Redux 的 3 个基本原则:
- 应用程序的整个状态存储在单个状态树中。
- 状态是只读的。
- 状态更改是通过仅使用纯函数(不改变对象,但返回全新对象的函数)的 reducer 进行的。
请参阅 官方文档 以更深入地了解 Redux。
这篇文章已更新为与 ngrx 4+ 兼容。 你需要 TypeScript 2.4+ 和 RxJS 5.4+。
在这篇文章中,我们将构建一个非常简单的待办事项应用程序,让我们添加、删除和更新待办事项以及将待办事项标记为已完成。
入门
首先,您需要 ngrx/store,它可以使用 npm 或 Yarn 安装在您的项目中:
# npm npm install @ngrx/store --save # Yarn yarn add @ngrx/store
我们的 Todo 减速器
现在让我们继续为我们的 todo 应用程序创建一个简单的 reducer。 如果你在这之前写过 reducer,你会很熟悉:
减速器/todo.reducer.ts
import { Action } from '@ngrx/store'; export const ADD_TODO = 'ADD_TODO'; export const DELETE_TODO = 'DELETE_TODO'; export const UPDATE_TODO = 'UPDATE_TODO'; export const TOGGLE_DONE = 'TOGGLE_DONE'; export interface ActionWithPayload<T> extends Action { payload: T; } export interface TodoPayload { index?: number; done?: boolean; value?: string; newValue?: string; }
动作有一个类型和一个可选的有效负载。 类型应该是一个字符串,所以在这里我们定义和导出保存我们不同类型的常量。 reducer 函数本身接受一个状态和一个动作,然后根据动作类型使用 switch 语句返回正确的状态。
我们的 switch 语句定义了一个 default 子句,它只返回状态,以防提供的操作与我们的任何预定义操作不匹配。
请注意,在 switch 语句中,我们的操作总是返回一个新状态,而不是改变当前状态。
配置应用模块
现在我们已经有了 reducer,我们可以使用 ngrx/store 模块和我们的 reducer 来配置 app 模块:
app.module.ts
// ... import { AppComponent } from './app.component'; import { StoreModule } from '@ngrx/store'; import { todoReducer } from './reducers/todo.reducer';
我们导入 StoreModule,然后使用 provideStore 方法和我们的 reducer 的名称将其添加到 NgModule 的导入中。
在组件中选择和调度
现在我们已经准备好 reducer 并正确配置了 app 模块,我们可以将 ngrx 的 Store 服务注入到我们的组件中。 然后就像使用 Store 服务来选择我们的数据并调度操作一样简单。
当使用 Store.select
选择数据时,返回值是一个 observable,这允许我们使用模板中的 异步管道 来管理我们对数据的订阅。
这是我们的组件类实现,我们突出显示了一些重要的项目:
app.component.ts
import { Component, OnInit } from '@angular/core'; import { Observable } from 'rxjs/Observable'; import { Store } from '@ngrx/store'; import { ADD_TODO, DELETE_TODO, UPDATE_TODO, TOGGLE_DONE } from './reducers/todo.reducer'; @Component({ selector: 'app-root', templateUrl: './app.component.html', styles: [ .done { text-decoration: line-through; color: salmon; } ] }) export class AppComponent implements OnInit { todos$: Observable<any>; todo: string; editing = false; indexToEdit: number | null; constructor(private store: Store<any>) {} ngOnInit() { this.todos$ = this.store.select('todoReducer'); } addTodo(value) { this.store.dispatch({ type: ADD_TODO, payload: { value, done: false } }); this.todo = ''; } deleteTodo(index) { this.store.dispatch({ type: DELETE_TODO, payload: { index } }); } editTodo(todo, index) { this.editing = true; this.todo = todo.value; this.indexToEdit = index; } cancelEdit() { this.editing = false; this.todo = ''; this.indexToEdit = null; } updateTodo(updatedTodo) { this.store.dispatch({ type: UPDATE_TODO, payload: { index: this.indexToEdit, newValue: updatedTodo } }); this.todo = ''; this.indexToEdit = null; this.editing = false; }
您可以看到我们的组件类非常简单,它所做的大部分工作都是将操作发送到商店。
组件模板
组件模板非常简单:
<input placeholder="your todo" [(ngModel)]="todo"> <button (click)="addTodo(todo)" [disabled]="!todo" *ngIf="!editing"> Add todo </button> <button (click)="updateTodo(todo)" *ngIf="editing"> Update </button> <button (click)="cancelEdit()" *ngIf="editing"> Cancel </button> <ul> <li *ngFor="let todo of todos$ | async; let i = index;"> <span [class.done]="todo.done">{{ todo.value }}</span> <button (click)="editTodo(todo, i)">Edit</button> <button (click)="toggleDone(todo, i)">Toggle Done</button> <button (click)="deleteTodo(i)">X</button> </li> </ul>
🍰 你有它! 一个非常简单但功能强大的 todo 应用程序,支持 Redux 风格的状态管理,这要归功于 ngrx/store。