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。