开始使用 ngrx 在 Angular 中进行 Redux 风格的状态管理

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风格的状态管理。

Published At
Categories with 技术
Tagged with
comments powered by Disqus