文档结构  
翻译进度:已翻译     翻译赏金:0 元 (?)    ¥ 我要打赏

Angular 2对许多特性使用了observables ,并且使用了observables 的API都非常健壮,这些api对应的依赖于Rxjs。 在现代应用中,社区采用单一的存储方式处理状态。 让我们使用Rxjs为我们的Angular应用创建一个响应式的易于使用的Store。

单一Store是一个最佳实践

我们将创建一个Store,在我们的应用中这是唯一的一个Store。通过这样做, 我们可以提供更好的体验,降低在我们的应用程序的状态推理的难度, 因为所有的状态是在一个地方! 首先让我们来为Store创建一个提供者

第 1 段(可获 1.4 积分)
export class AppStore {}

增加一个主题

现在我们的Store几乎什么都不做. 我希望这个Store有响应式的api并且在我们的应用中使用它. 我们将使用RxJs创建一个主题. 一个主题对我们的Store来说是非常合理的,因为我们可以同时传送信息到多个观察者.这就意味着我们可以设置很多的监听器. 这将允许在其他的组件(Component)和提供者(Providers)中订阅我们的Store。 我们需要始终知道当前的状态是什么, 当一个新的观察者订阅这个主题的时候, 这个主题应该提供观察者当前的状态. 幸运的是,这有一个特殊的主题, 一个 行为主题.让我们Store具有响应式的功能吧!

第 2 段(可获 1.51 积分)
import { BehaviorSubject } from 'rxjs/BehaviorSubject';

const store = new BehaviorSubject(); 

export class AppStore {
  store = store;
}

上面我们在类的外部创建了一个Store实例,确保Store在任何情况下都只有一个实例 不管Angular如何注入和实例化AppStore. 现在让我们为我们的Store设置一个默认值.

import { BehaviorSubject } from 'rxjs/BehaviorSubject';

const state = {
  user: {},
  isLoading: false,
  items: []
};

const store = new BehaviorSubject<any>(state); 

export class AppStore {
  store = store;
}
第 3 段(可获 0.49 积分)

订阅

在这一点上, 我们已经准备好在我们的应用中使用AppStore了! 是的, 基本上是这样, 惊讶不? 虽然我们可以在这里停下来, 我们应该使它非常容易处理存储在我们的应用程序中. 第一件事情就是设置一种方法,能够在我们的app中的任何地方来订阅这个Store的变化。

export class AppStore {
  store = store;
  changes = store.asObservable();
}

我们将Store转换成可观察的,以便我们可以订阅它, 这个changes是能够被观察到的。 现在我们所要做的就是在我们的应用程序的任何地方订阅,这样我们将能够看到Store的这些变化. 我们也应该有一种方法来获得当前状态在任何给定的时间,而无需等待改变。

第 4 段(可获 1.56 积分)
export class AppStore {
  store = store;
  changes = store.asObservable();

  getState() {
    return this.store.value;
  }
}

一个行为主题(BehaviorSubject) 允许我们通过value的属性值同步访问当前状态。. 我们现在可以订阅和访问当前状态变化, 让我们创建一个简单的方法使这些状态改变到Store.

更新

我们将继续让Store在我们的应用中更加容易使用,通过创建一个简单的方法来更新Store。 因为我们的状态在Store中,我们不能仅仅只改变状态,然后期待Store能够(自动)更新。 在这一点上你失去了单一Store的好处,而且随着应用规模的增长会更加混乱不堪。 首先为我们的Store创建一个接口。

第 5 段(可获 1.39 积分)
interface State {
  user: Object;
  isLoading: boolean;
  items: any[];
}

现在,我们有了这个接口, 我们可以确保新的Store更新永远是我们应用的最新状态。 接下类我们将创建一个更新状态的方法, 当状态更新的时候Store也将会更新.

export class AppStore {
  // ...

  setState(state: State) { // use type here
  // will trigger all subscriptions to this.changes
    this.store.next(state); 
  }
}

我们的Store现在看起来非常酷! 到目前为止,我们可以订阅对Store状态的更改并创建状态更改.. 将此Store添加到组件并使用它。

第 6 段(可获 0.89 积分)

使用Store

使用之前确保AppStore已经注入。 现在,在一个组件中…

import { Component } from '@angular/core';
import { Store } from './store';
import 'rxjs/Rx';

@Component({
  selector: 'app',
  template: `
    <div *ngIf="isLoading">...loading</div>
  `
})
class App {
  isLoading: boolean = false;
  constructor(private store: AppStore) {
    this.store
    .changes
    .pluck('isLoading')
    .subscribe((isLoading: boolean) => this.isLoader = isLoading)
  }
}

一旦我们有了Store, 我们要做的就是订阅它的变化。 然后我们使用pluck操作从Store中快捷获取 isLoading属性然后绑定它到当前类中的isLoading属性上。 现在,每次调用 setState, 这个订阅回调函数都会被调用。

第 7 段(可获 0.81 积分)
class App {
  // ...
  showLoader(isLoading: boolean) {
    const currentState = this.store.getState();
    currentState.isLoading = isLoading
    this.store.setState(currentState);
  }
}

这个更新函数接收一个名称和更新isLoading为当前的状态值,然后调用Store中的setState函数。这样看起来好像没什么问题,所有的正常工作,但是这不是我们想要的。我们直接更改了这个状态,而且完全绕过了Store。首先,这个Store的目的就有点失败。所有状态变化,甚至嵌套状态,都必须经过Store。让我们确保我们不会更改Store,确保单项数据流,是从Store推送更新到我们的应用,然后我们的应用处理这些更新。就是一个大圆圈。

第 8 段(可获 1.29 积分)
changes = store.asObservable().distinctUntilChanged()

通过使用distinctUntilChanged函数, 这个Store将不会推送更新,除非设置的是一个完全不同的对象。 现在我们必须更改我们组件中更新Store状态的代码, 因为它目前的实现不会触发改变。

class App {
  // ...
  showLoader(isLoading: boolean) {
    const currentState = this.store.getState();
    this.store.setState(Object.assign({}, currentState, { isLoading }));
  }
}

使用 Object.assign或者别的合并策略, 我们创建一个包含isLoading属性的新对象。 这个状态将会被推。因为我们在构造函数订阅了, 当本地状态改变或更新的时候,组件将能够接收到通知。一切都趋于完整!我们使用不变Store的另外一个好处是,现在可以对我们的组件做一些性能优化,比如改变我们组件的变化检测策略。 我承诺利用这个单一Store会有一个更好的开发流程, 所以没有合并一些复杂的开发工具,让我们创建一些日志记录中间件!

第 9 段(可获 1.76 积分)
import 'rxjs/Rx';

export class AppStore {
  store = store;
  changes = store
  .asObservable()
  .distinctUntilChanged()
  // log new state
  .do(changes => console.log('new state', changes))

  getState() {
    return this.store.value;
  }

  setState(state: State) {
    console.log('setState ', state); // log update
    this.store.next(state); 
  }
}

这很容易。 在(状态)变化时使用do操作,,我们可以记录下新的状态到日志。然后再 setState者边, 我们可以记录下正在设置的状态。 这两个值不会总是相同的.。do操作的中记录的更改,只会记录那种不可变更改(一个全新的对象),在setState函数中,将会记录任何尝试更改状态的行为到日志中。这非常有利于我们调试。现在一起来。

第 10 段(可获 0.79 积分)

结论

这是一个很好的起点,对于在你的Angular 2 应用中创建一个状态管理方案来说。 要让这更加容易还有很多的事情可以做,像摆脱需要执行一成不变的状态变化的样板。 你可以在这里免费看到Angular2基础课程, 我们在那里做的。

第 11 段(可获 0.78 积分)

文章评论