Angular中用于Redux风格状态管理的ngrx入门
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。