ngRx 官方示例分析 - 4.pages
Page 中通过构造函数注入 Store,基于 Store 进行数据操作。
注意 Component 使用了 changeDetection: ChangeDetectionStrategy.OnPush.
OnPush means that the change detector's mode will be set to CheckOnce during hydration.
/app/containers/collection-page.ts
import 'rxjs/add/operator/let';
import { Component, ChangeDetectionStrategy } from '@angular/core';
import { Store } from '@ngrx/store';
import { Observable } from 'rxjs/Observable'; import * as fromRoot from '../reducers';
import { Book } from '../models/book'; @Component({
selector: 'bc-collection-page',
changeDetection: ChangeDetectionStrategy.OnPush,
template: `
<md-card>
<md-card-title>My Collection</md-card-title>
</md-card> <bc-book-preview-list [books]="books$ | async"></bc-book-preview-list>
`,
/**
* Container components are permitted to have just enough styles
* to bring the view together. If the number of styles grow,
* consider breaking them out into presentational
* components.
*/
styles: [`
md-card-title {
display: flex;
justify-content: center;
}
`]
})
export class CollectionPageComponent {
books$: Observable<Book[]>; constructor(store: Store<fromRoot.State>) {
this.books$ = store.select(fromRoot.getBookCollection);
}
}
/app/containers/find-book-page.ts
import 'rxjs/add/operator/let';
import 'rxjs/add/operator/take';
import { Component, ChangeDetectionStrategy } from '@angular/core';
import { Store } from '@ngrx/store';
import { Observable } from 'rxjs/Observable'; import * as fromRoot from '../reducers';
import * as book from '../actions/book';
import { Book } from '../models/book'; @Component({
selector: 'bc-find-book-page',
changeDetection: ChangeDetectionStrategy.OnPush,
template: `
<bc-book-search [query]="searchQuery$ | async" [searching]="loading$ | async" (search)="search($event)"></bc-book-search>
<bc-book-preview-list [books]="books$ | async"></bc-book-preview-list>
`
})
export class FindBookPageComponent {
searchQuery$: Observable<string>;
books$: Observable<Book[]>;
loading$: Observable<boolean>; constructor(private store: Store<fromRoot.State>) {
this.searchQuery$ = store.select(fromRoot.getSearchQuery).take(1);
this.books$ = store.select(fromRoot.getSearchResults);
this.loading$ = store.select(fromRoot.getSearchLoading);
} search(query: string) {
this.store.dispatch(new book.SearchAction(query));
}
}
注意,点击搜索之后,我们回派发一个 Search 的 Action,但是,在 Book 的 Reducer 中并不处理这个 Action, @ngrx/effect 将会监控这个 Action,进行异步处理。
/app/containers/not-found-page.ts
import { Component, ChangeDetectionStrategy } from '@angular/core';
@Component({
  selector: 'bc-not-found-page',
  changeDetection: ChangeDetectionStrategy.OnPush,
  template: `
    <md-card>
      <md-card-title>404: Not Found</md-card-title>
      <md-card-content>
        <p>Hey! It looks like this page doesn't exist yet.</p>
      </md-card-content>
      <md-card-actions>
        <button md-raised-button color="primary" routerLink="/">Take Me Home</button>
      </md-card-actions>
    </md-card>
  `,
  styles: [`
    :host {
      text-align: center;
    }
  `]
})
export class NotFoundPageComponent { }
通过 @Input() 参数将数据从页面传递给下面的 Component,事件从底层 Component 冒泡上来。
/app/containers/selected-book-page.ts
import { Component, ChangeDetectionStrategy } from '@angular/core';
import { Store } from '@ngrx/store';
import { Observable } from 'rxjs/Observable';
import * as fromRoot from '../reducers';
import * as collection from '../actions/collection';
import { Book } from '../models/book';
@Component({
  selector: 'bc-selected-book-page',
  changeDetection: ChangeDetectionStrategy.OnPush,
  template: `
    <bc-book-detail
      [book]="book$ | async"
      [inCollection]="isSelectedBookInCollection$ | async"
      (add)="addToCollection($event)"
      (remove)="removeFromCollection($event)">
    </bc-book-detail>
  `
})
export class SelectedBookPageComponent {
  book$: Observable<Book>;
  isSelectedBookInCollection$: Observable<boolean>;
  constructor(private store: Store<fromRoot.State>) {
    this.book$ = store.select(fromRoot.getSelectedBook);
    this.isSelectedBookInCollection$ = store.select(fromRoot.isSelectedBookInCollection);
  }
  addToCollection(book: Book) {
    this.store.dispatch(new collection.AddBookAction(book));
  }
  removeFromCollection(book: Book) {
    this.store.dispatch(new collection.RemoveBookAction(book));
  }
}
/app/containers/view-book-page.ts
import '@ngrx/core/add/operator/select';
import 'rxjs/add/operator/map';
import { Component, OnDestroy, ChangeDetectionStrategy } from '@angular/core';
import { ActivatedRoute } from '@angular/router';
import { Store } from '@ngrx/store';
import { Subscription } from 'rxjs/Subscription'; import * as fromRoot from '../reducers';
import * as book from '../actions/book'; /**
* Note: Container components are also reusable. Whether or not
* a component is a presentation component or a container
* component is an implementation detail.
*
* The View Book Page's responsibility is to map router params
* to a 'Select' book action. Actually showing the selected
* book remains a responsibility of the
* SelectedBookPageComponent
*/
@Component({
selector: 'bc-view-book-page',
changeDetection: ChangeDetectionStrategy.OnPush,
template: `
<bc-selected-book-page></bc-selected-book-page>
`
})
export class ViewBookPageComponent implements OnDestroy {
actionsSubscription: Subscription; constructor(store: Store<fromRoot.State>, route: ActivatedRoute) {
this.actionsSubscription = route.params
.select<string>('id')
.map(id => new book.SelectAction(id))
.subscribe(store);
} ngOnDestroy() {
this.actionsSubscription.unsubscribe();
}
}
import 'rxjs/add/operator/let';
import { Observable } from 'rxjs/Observable';
import { Component, ChangeDetectionStrategy } from '@angular/core';
import { Store } from '@ngrx/store'; import * as fromRoot from '../reducers';
import * as layout from '../actions/layout'; @Component({
selector: 'bc-app',
changeDetection: ChangeDetectionStrategy.OnPush,
template: `
<bc-layout>
<bc-sidenav [open]="showSidenav$ | async">
<bc-nav-item (activate)="closeSidenav()" routerLink="/" icon="book" hint="View your book collection">
My Collection
</bc-nav-item>
<bc-nav-item (activate)="closeSidenav()" routerLink="/book/find" icon="search" hint="Find your next book!">
Browse Books
</bc-nav-item>
</bc-sidenav>
<bc-toolbar (openMenu)="openSidenav()">
Book Collection
</bc-toolbar> <router-outlet></router-outlet>
</bc-layout>
`
})
export class AppComponent {
showSidenav$: Observable<boolean>; constructor(private store: Store<fromRoot.State>) {
/**
* Selectors can be applied with the `select` operator which passes the state
* tree to the provided selector
*/
this.showSidenav$ = this.store.select(fromRoot.getShowSidenav);
} closeSidenav() {
/**
* All state updates are handled through dispatched actions in 'container'
* components. This provides a clear, reproducible history of state
* updates and user interaction through the life of our
* application.
*/
this.store.dispatch(new layout.CloseSidenavAction());
} openSidenav() {
this.store.dispatch(new layout.OpenSidenavAction());
}
}
ngRx 官方示例分析 - 4.pages的更多相关文章
- ngRx 官方示例分析 - 3. reducers
		
上一篇:ngRx 官方示例分析 - 2. Action 管理 这里我们讨论 reducer. 如果你注意的话,会看到在不同的 Action 定义文件中,导出的 Action 类型名称都是 Action ...
 - ngRx 官方示例分析 - 2. Action 管理
		
我们从 Action 名称开始. 解决 Action 名称冲突问题 在 ngRx 中,不同的 Action 需要一个 Action Type 进行区分,一般来说,这个 Action Type 是一个字 ...
 - ngRx 官方示例分析 - 1. 介绍
		
ngRx 的官方示例演示了在具体的场景中,如何使用 ngRx 管理应用的状态. 示例介绍 示例允许用户通过查询 google 的 book API 来查询图书,并保存自己的精选书籍列表. 菜单有两 ...
 - ngRx 官方示例分析 - 6 - Effect
		
@ngrx/effect 前面我们提到,在 Book 的 reducer 中,并没有 Search 这个 Action 的处理,由于它需要发出一个异步的请求,等到请求返回前端,我们需要根据返回的结果来 ...
 - ngRx 官方示例分析 - 5. components
		
组件通过标准的 Input 和 Output 进行操作,并不直接访问 store. /app/components/book-authors.ts import { Component, Input ...
 - RocketMQ源码分析之从官方示例窥探:RocketMQ事务消息实现基本思想
		
摘要: RocketMQ源码分析之从官方示例窥探RocketMQ事务消息实现基本思想. 在阅读本文前,若您对RocketMQ技术感兴趣,请加入RocketMQ技术交流群 RocketMQ4.3.0版本 ...
 - Halcon斑点分析官方示例讲解
		
官方示例中有许多很好的例子可以帮助大家理解和学习Halcon,下面举几个经典的斑点分析例子讲解一下 Crystals 图中显示了在高层大气中采集到的晶体样本的图像.任务是分析对象以确定特定形状的频率. ...
 - DotNetBar for Windows Forms 12.7.0.10_冰河之刃重打包版原创发布-带官方示例程序版
		
关于 DotNetBar for Windows Forms 12.7.0.10_冰河之刃重打包版 --------------------11.8.0.8_冰河之刃重打包版------------- ...
 - DotNetBar for Windows Forms 12.5.0.2_冰河之刃重打包版原创发布-带官方示例程序版
		
关于 DotNetBar for Windows Forms 12.5.0.2_冰河之刃重打包版 --------------------11.8.0.8_冰河之刃重打包版-------------- ...
 
随机推荐
- Kettle中忽略错误行继续执行
			
在kettle执行的过程中,如果遇到错误,kettle会停止运行.在某些时候,并不希望kettle停止运行,所以就要处理下这些错误行. 例如这两天发现在一个转换中,总数出现一些不规则数据,这些数据一出 ...
 - Android手机通过APN设置上网的方法
			
今天一个朋友问了我关于android网络设置的问题,感觉还是挺有趣,特分享如下: 他是在香港买了一款LGP500的手机,系统是android系统,但是回来之后不能上网,于是在网上搜了很多资料,但是设置 ...
 - SpringMVC  ModelAndView、Map、Model、ModelMap
			
目标方法返回值可以是ModelAndView .Map.Model.ModelMap类型,但最根本还都是ModelAndView. 其中可以包含试图和模型信息. SpringMVC 会把ModelAn ...
 - Spring MVC报错:The request sent by the client was syntactically incorrect ()
			
原因: 1.参数名称不一致 2.参数类型不一致
 - [js高手之路]从零开始打造一个javascript开源框架gdom与插件开发免费视频教程连载中
			
百度网盘下载地址:https://pan.baidu.com/s/1kULNXOF 优酷土豆观看地址:http://v.youku.com/v_show/id_XMzAwNTY2MTE0MA==.ht ...
 - python3基础(二)
			
loops循环语句 一 if语句,if语句配合else使用,可以没有else. 单分支if语句 age = input('Age:') password = '67' if age == passwo ...
 - 【Win 10 应用开发】MIDI 音乐合成——更改乐器音色
			
在开始今天的吹 BB 博文之前,说点题外话. 首先,上次老周给大伙伴们介绍完发送 MIDI 音符,本来说好的接着说一下如何更改乐器音色,为啥这么久都没更新呢.特特来解释一下,最近老周接了一个 ASP. ...
 - PE文件详解(三)
			
本文转自小甲鱼的PE文件详解系列传送门 PE文件到内存的映射 在执行一个PE文件的时候,windows 并不在一开始就将整个文件读入内存的,二十采用与内存映射文件类似的机制. 也就是说,windows ...
 - 如何利用git shell提交代码到github
			
在很早之前我根据找到的一些资料以及自己的实践总结了一篇如何将VS2015上的代码上传到GitHub上,后来我发现有小伙伴私信我,说跟我上面写的不一样,但是那段时间也比较忙,当我发现有人私信的时候差不过 ...
 - 【知了堂学习笔记】/JavaScript对象--/暖妮
			
JavaScript对象 1.什么是JavaScript对象? JavaScript 中的所有事物都是对象:字符串.数字.数组.日期,等等. 在 JavaScript 中,对象是拥有属性和方法的数据. ...