我的Angular2项目:
原文地址:
调用所有服务
首先,将Http和Headers从angular2/http模块导入到应用中,准备Http调用。
import {Http, Headers} from 'angular2/http';
然后,我们定义一个BASE_URL常量,所以我们只需要键入一次,我们也将创建一个HEADER常量来告诉我们服务器我们如何与它进行通信。这可能不是必需的,这取决于你正在使用的后端,但是要让json-server工作,我不得不添加它。
const BASE_URL = 'http://localhost:3000/items/';const HEADER = { headers: new Headers({ 'Content-Type': 'application/json' }) };
我们修改ItemsService的构造器,将Http对象作为类的一个http属性注入进来。
constructor(private http: Http, private store: Store) { this.items = store.select('items');}
从这里,让我们修改我们的CRUD方法来处理远程服务器调用,从loadItems开始。我们正在调用this.http.get(BASE_URL)来获取我们的远程items,并且因为Http返回一个observable,所以我们可以通过额外的操作来管理结果。我们将调用map来解析返回结果然后再调用map来创建一个对象然后分发给对应的reducer。map操作的返回结果是一个Observable对象,因为每一个结果都是通过它来操作序列的。为了“捆绑”序列,我们将订阅它,然后通过调度我们的转换结果将控制权交给我们的reducer。
loadItems() { // Retrieves the items collection, parses the JSON, creates an event with the JSON as a payload, // and dispatches that event this.http.get(BASE_URL) .map(res => res.json()) .map(payload => ({ type: 'ADD_ITEMS', payload })) .subscribe(action => this.store.dispatch(action));}
当我们更新createItem时,我们将会遵循类似的模式。唯一的不同是,我们使用http.post和格式化了的请求体以及HEADER常量来访问服务器。一旦我们有了返回结果,我们将所有内容映射到我们可以在我们的订阅方法中发送的对象。
createItem(item: Item) { this.http.post(BASE_URL, JSON.stringify(item), HEADER) .map(res => res.json()) .map(payload => ({ type: 'CREATE_ITEM', payload })) .subscribe(action => this.store.dispatch(action));}
更新和删除有点简单,因为我们不依赖于从服务器返回的对象。我们只需要关注操作是否成功。因为这些,我们将使用http.put和http.delete,然后跳过返回结果的映射这一步。我们可以从subscribe中分发一个动作到reducer。看下面的代码:
updateItem(item: Item) { this.http.put(`${BASE_URL}${item.id}`, JSON.stringify(item), HEADER) .subscribe(action => this.store.dispatch({ type: 'UPDATE_ITEM', payload: item }));}deleteItem(item: Item) { this.http.delete(`${BASE_URL}${item.id}`) .subscribe(action => this.store.dispatch({ type: 'DELETE_ITEM', payload: item }));}
测试
redux的最重要的方面之一是测试reducer是非常容易的,因为它们是具有明确意图的纯函数。关于我们的应用,包含可测试逻辑的表面积已大大减少。当我写这些的时候我并没有想搞笑,但事后看来,那就是!
配置
我不会进入整个测试工具,而是快速浏览我们的测试规范。我们需要做的第一步是导入items和selectedItems以及从angular2/testing中导入it,describe和expect。稍等。这不是Jasmine的方法吗??是的,Angular2默认使用的就是Jasmine。
import {items, selectedItem} from './items';import { it, describe, expect} from 'angular2/testing';
作为参考,我们的规格的骨架看起来像这样。
describe('Items', () => { describe('selectedItem store', () => { it('returns null by default', () => {}); it('SELECT_ITEM returns the provided payload', () => {}); }); describe('items store', () => { let initialState = [ { id: 0, name: 'First Item' }, { id: 1, name: 'Second Item' } ]; it('returns an empty array by default', () => {}); it('ADD_ITEMS', () => {}); it('CREATE_ITEM', () => {}); it('UPDATE_ITEM', () => {}); it('DELETE_ITEM', () => {}); });});
测试真的很容易写,因为我们从一个初始状态开始,当我们向我们的reducer发送一个动作时,我们知道我们应该得到什么。我们知道,如果我们发出ADD_ITEMS的动作,我们将收回我们在有效载荷(payload)中的任何内容,我们在下面的断言中看到。
it('ADD_ITEMS', () => { let payload = initialState, stateItems = items([], {type: 'ADD_ITEMS', payload: payload}); // Don't forget to include an initial stateexpect(stateItems).toEqual(payload);});
如果我们使用CREATE_ITEM的动作类型调用items reducer,那么我们预期结果将是初始数组加上新的记录。
it('CREATE_ITEM', () => { let payload = {id: 2, name: 'added item'}, result = [...initialState, payload], stateItems = items(initialState, {type: 'CREATE_ITEM', payload: payload});expect(stateItems).toEqual(result);});
我们可以轻松地阐述剩下的两个reducer的方法的预期结果,然后为我们写下如下所示的断言。
it('UPDATE_ITEM', () => { let payload = { id: 1, name: 'Updated Item' }, result = [ initialState[0], { id: 1, name: 'Updated Item' } ], stateItems = items(initialState, {type: 'UPDATE_ITEM', payload: payload});expect(stateItems).toEqual(result);});it('DELETE_ITEM', () => { let payload = { id: 0 }, result = [ initialState[1] ], stateItems = items(initialState, {type: 'DELETE_ITEM', payload: payload});expect(stateItems).toEqual(result);});
回顾
我们已经在本文中讲了很多,如果你已经做到了这一点! 让我们快速回顾一下我们所做的工作。
-
redux的核心特性是统一的状态,事件向上以及自顶向下的状态流。
-
@ngrx/store实现使用observables可以让我们使用异步管道填充我们的模板。
3.我们创建了reducers,它接收一个动作和一个状态,并且返回一个新的状态对象。
4.我们的reducer功能必须是纯粹的,所以我们看到了如何创建它们而不会使我们的集合改变。
5.一个store是一个基本的键值对map,和一些处理事件和发射状态的机制。
6.通过使用store.emit来广播事件。
7.我们使用store.select来订阅数据。
8.使用表单创建本地副本以避免更高级别的改变。
9.使用异步调用,我们通过Observable序列传递我们的结果,然后在完成时将该事件发送到reducer。
10.reducer非常易于测试,因为方法非常纯净。
通过@ngrx/store学习redux一直是我在一段时间内感受到的那种“新程序员”的感觉。非常好玩,对不对?? 举个例子,玩弄一下,思考如何在日常项目中使用这种方法。