Redux模式是管理Web应用程序中状态的一种非常强大的方式,尤其是在应用程序变得更加复杂的情况下。Redux这个库最常与Reaction一起使用,但多亏了ngrx/Store库,再加上RxJS的强大功能,我们可以在角度应用程序中以类似Redux的方式管理我们应用程序的状态。
下面是Redux的三个基本原则的快速回顾:
- 应用程序的整个状态存储在单个状态树中。
- 状态为只读。
- 状态更改是通过仅使用纯函数的减法器进行的(不变异对象的函数,而是返回完全新的对象的函数)。
<$>[note]请参阅官方文档以更深入地了解Redux。<$>
<$>[注意]此帖子已更新为与ngrx 4+ 兼容。您需要打字脚本** 2.4+** 和** RxJS 5.4+** 。<$>
在这篇文章中,我们将构建一个非常简单的待办事项应用程序,让我们添加、删除和更新待办事项,并将待办事项标记为已完成。
入门
首先,您需要ngrx/STORE,它可以与npm或Yarn:一起安装在您的项目中
1# npm
2npm install @ngrx/store --save
3
4# Yarn
5yarn add @ngrx/store
我们的TODO减速器
现在,让我们继续为我们的ToDo应用程序创建一个简单的Reducer。如果您以前编写过Reducer,那么您应该很熟悉以下内容:
1[label reducers/todo.reducer.ts]
2import { Action } from '@ngrx/store';
3
4export const ADD_TODO = 'ADD_TODO';
5export const DELETE_TODO = 'DELETE_TODO';
6export const UPDATE_TODO = 'UPDATE_TODO';
7export const TOGGLE_DONE = 'TOGGLE_DONE';
8export interface ActionWithPayload<T> extends Action {
9 payload: T;
10}
11export interface TodoPayload {
12 index?: number;
13 done?: boolean;
14 value?: string;
15 newValue?: string;
16}
操作有一个类型和一个可选的有效负载。类型应该是字符串,所以在这里我们定义并导出保存不同类型的常量。Reducer函数本身接受状态和操作,然后使用Switch语句根据操作类型返回正确的状态。
我们的Switch语句定义了一个默认子句,在提供的操作与我们预定义的任何操作都不匹配的情况下,该子句只返回状态。
请注意,在Switch语句中,我们的操作总是返回新状态,而不是改变当前状态。
配置App模块
现在我们已经准备好了减速器,我们可以使用ngrx/store模块和减速器来配置应用程序模块:
1[label app.module.ts]
2// ...
3
4import { AppComponent } from './app.component';
5import { StoreModule } from '@ngrx/store';
6import { todoReducer } from './reducers/todo.reducer';
我们导入StoreModule,然后使用ProvideStore方法和Reducer的名称将其添加到NgModule的导入中。
组件中的选择和调度
既然我们已经准备好了减速器并正确配置了应用程序模块,我们就可以将ngrx的Store服务注入到我们的组件中了。然后,只需使用Store服务选择数据并分派操作即可。
当使用Store.selt
选择数据时,返回值是一个可观察的对象,允许我们使用模板中的异步pipe]来管理我们对数据的订阅。
以下是我们的组件类实现,我们重点介绍了几个重要的项目:
1[label app.component.ts]
2import { Component, OnInit } from '@angular/core';
3import { Observable } from 'rxjs/Observable';
4
5import { Store } from '@ngrx/store';
6import { ADD_TODO, DELETE_TODO, UPDATE_TODO, TOGGLE_DONE }
7 from './reducers/todo.reducer';
8@Component({
9 selector: 'app-root',
10 templateUrl: './app.component.html',
11 styles: [
12 .done { text-decoration: line-through; color: salmon; }
13 ]
14})
15export class AppComponent implements OnInit {
16 todos$: Observable<any>;
17 todo: string;
18 editing = false;
19 indexToEdit: number | null;
20 constructor(private store: Store<any>) {}
21 ngOnInit() {
22 this.todos$ = this.store.select('todoReducer');
23 }
24 addTodo(value) {
25 this.store.dispatch({ type: ADD_TODO, payload: { value, done: false } });
26 this.todo = '';
27 }
28 deleteTodo(index) {
29 this.store.dispatch({ type: DELETE_TODO, payload: { index } });
30 }
31 editTodo(todo, index) {
32 this.editing = true;
33 this.todo = todo.value;
34 this.indexToEdit = index;
35 }
36 cancelEdit() {
37 this.editing = false;
38 this.todo = '';
39 this.indexToEdit = null;
40 }
41 updateTodo(updatedTodo) {
42 this.store.dispatch({ type: UPDATE_TODO, payload: { index: this.indexToEdit, newValue: updatedTodo } });
43 this.todo = '';
44 this.indexToEdit = null;
45 this.editing = false;
46 }
你可以看到我们的组件类非常简单,它所做的大部分工作就是将动作分派到存储中。
组件模板
组件模板就像它得到的一样简单:
1<input placeholder="your todo" [(ngModel)]="todo">
2
3<button
4 (click)="addTodo(todo)"
5 [disabled]="!todo"
6 *ngIf="!editing">
7 Add todo
8</button>
9
10<button
11 (click)="updateTodo(todo)"
12 *ngIf="editing">
13 Update
14</button>
15<button
16 (click)="cancelEdit()"
17 *ngIf="editing">
18 Cancel
19</button>
20
21<ul>
22 <li *ngFor="let todo of todos$ | async; let i = index;">
23 <span [class.done]="todo.done">{{ todo.value }}</span>
24 <button (click)="editTodo(todo, i)">Edit</button>
25 <button (click)="toggleDone(todo, i)">Toggle Done</button>
26 <button (click)="deleteTodo(i)">X</button>
27 </li>
28</ul>
🍰,就是这样!多亏了ngrx/store,一个非常简单但功能强大的待办事项应用程序采用了Redux风格的状态管理。