See the current implementaion of code, we have a smart component, and inside the smart component we are using both 'serivce' and 'store'.

In the large application, what we really want is one service to handle the application state instead of two or more. And also we need response to the user action to get new data, all the requirements actaully can be handled by 'Store'.

import {Component, OnInit} from '@angular/core';
import {Store} from '@ngrx/store';
import {ThreadsService} from "../services/threads.service";
import {AppState} from "../store/application-state";
import {AllUserData} from "../../../shared/to/all-user-data";
import {LoadUserThreadsAction} from "../store/actions";
import {Observable} from "rxjs";
import 'rxjs/add/operator/map';
import 'rxjs/add/operator/skip';
import {values, keys, last} from 'ramda';
import {Thread} from "../../../shared/model/thread.interface";
import {ThreadSummary} from "./model/threadSummary.interface"; @Component({
selector: 'thread-section',
templateUrl: './thread-section.component.html',
styleUrls: ['./thread-section.component.css']
})
export class ThreadSectionComponent implements OnInit { userName$: Observable<string>;
counterOfUnreadMessages$: Observable<number>;
threadSummary$: Observable<ThreadSummary[]>; constructor(private store: Store<AppState>,
private threadsService: ThreadsService) { this.userName$ = store.select(this.userNameSelector); this.counterOfUnreadMessages$ = store.select(this.unreadMessageCounterSelector); this.threadSummary$ = store.select(this.mapStateToThreadSummarySelector.bind(this))
} mapStateToThreadSummarySelector(state: AppState): ThreadSummary[] {
const threads = values<Thread>(state.storeData.threads);
return threads.map((thread) => this.mapThreadToThreadSummary(thread, state));
} mapThreadToThreadSummary(thread: Thread, state: AppState): ThreadSummary {
const names: string = keys(thread.participants)
.map(participantId => state.storeData.participants[participantId].name)
.join(', ');
const lastMessageId: number = last(thread.messageIds);
const lastMessage = state.storeData.messages[lastMessageId];
return {
id: thread.id,
participants: names,
lastMessage: lastMessage.text,
timestamp: lastMessage.timestamp
};
} userNameSelector(state: AppState): string {
const currentUserId = state.uiState.userId;
const currentParticipant = state.storeData.participants[currentUserId]; if (!currentParticipant) {
return "";
} return currentParticipant.name;
} unreadMessageCounterSelector(state: AppState): number {
const currentUserId: number = state.uiState.userId; if (!currentUserId) {
return ;
} return values<Thread>(state.storeData.threads)
.reduce(
(acc: number, thread) => acc + (thread.participants[currentUserId] || )
, );
} ngOnInit() { this.threadsService.loadUserThreads()
.subscribe((allUserData: AllUserData) => {
this.store.dispatch(new LoadUserThreadsAction(allUserData))
});
} }

So what we want to do to improve the code is to "remove the service from the component, let it handle by ngrx/effect" lib.

Here instead we call the service to get data, we will dispatch an action call 'LoadUserTreadsAction', and inside this action, will have side effect either "UserTreadsLoadSuccess" or "UserTreadsLoadError".

Create a effect service:

import {Injectable} from '@angular/core';
import {Action} from '@ngrx/store';
import {Actions, Effect} from "@ngrx/effects";
import {ThreadsService} from "../../services/threads.service";
import {LOAD_USER_THREADS_ACTION, LoadUserThreadsSuccess} from "../actions";
import {Observable} from "rxjs"; @Injectable()
export class LoadUserThreadsEffectService { constructor(private action$: Actions, private threadsService: ThreadsService) {
} @Effect()
userThreadsEffect$: Observable<Action> = this.action$
.ofType(LOAD_USER_THREADS_ACTION) // only react for LOAD_USER_THREADS_ACTION
.switchMap(() => this.threadsService.loadUserThreads()) // get data from service
.map((allUserData) => new LoadUserThreadsSuccess(allUserData)) // After get data, dispatch success action
}

And of course, we need to import the lib:

..
import {EffectsModule} from "@ngrx/effects";
import {LoadUserThreadsEffectService} from "./store/effects/load-user-threads.service"; @NgModule({
declarations: [
AppComponent
],
imports: [
..
EffectsModule.run(LoadUserThreadsEffectService),
],
providers: [
ThreadsService
],
bootstrap: [AppComponent]
})
export class AppModule {
}

We need to change reudcer, instead of add case for 'LOAD_USER_THREAD_ACTION', we should do 'LOAD_USER_THREADS_SUCCESS':

export function storeReducer(state: AppState = INITIAL_APPLICATION_STATE, action: Action): AppState {

  switch(action.type) {
case LOAD_USER_THREADS_SUCCESS:
return handleLoadUserThreadsAction(state, action);
default:
return state;
}
}

Last, in our component, we dispatch 'LoadUserThreadsAction':

  ngOnInit() {

    this.store.dispatch(new LoadUserThreadsAction())
}

Github

[Angular] NgRx/effect, why to use it?的更多相关文章

  1. [Angular] How to get Store state in ngrx Effect

    For example, what you want to do is navgiate from current item to next or previous item. In your com ...

  2. [Angular] Ngrx/effects, Action trigger another action

    @Injectable() export class LoadUserThreadsEffectService { constructor(private action$: Actions, priv ...

  3. ngRx 官方示例分析 - 6 - Effect

    @ngrx/effect 前面我们提到,在 Book 的 reducer 中,并没有 Search 这个 Action 的处理,由于它需要发出一个异步的请求,等到请求返回前端,我们需要根据返回的结果来 ...

  4. [转]VS Code 扩展 Angular 6 Snippets - TypeScript, Html, Angular Material, ngRx, RxJS & Flex Layout

    本文转自:https://marketplace.visualstudio.com/items?itemName=Mikael.Angular-BeastCode VSCode Angular Typ ...

  5. 手把手教你用ngrx管理Angular状态

    本文将与你一起探讨如何用不可变数据储存的方式进行Angular应用的状态管理 :ngrx/store——Angular的响应式Redux.本文将会完成一个小型简单的Angular应用,最终代码可以在这 ...

  6. 如何在AngularX 中 使用ngrx

    ngrx 是 Angular框架的状态容器,提供可预测化的状态管理. 1.首先创建一个可路由访问的模块 这里命名为:DemopetModule. 包括文件:demopet.html.demopet.s ...

  7. ngRx 官方示例分析 - 4.pages

    Page 中通过构造函数注入 Store,基于 Store 进行数据操作. 注意 Component 使用了 changeDetection: ChangeDetectionStrategy.OnPu ...

  8. ngRx 官方示例分析 - 3. reducers

    上一篇:ngRx 官方示例分析 - 2. Action 管理 这里我们讨论 reducer. 如果你注意的话,会看到在不同的 Action 定义文件中,导出的 Action 类型名称都是 Action ...

  9. angular版聊天室|仿微信界面IM聊天|NG2+Node聊天实例

    一.项目介绍 运用angular+angular-cli+angular-router+ngrx/store+rxjs+webpack+node+wcPop等技术实现开发的仿微信angular版聊天室 ...

随机推荐

  1. JS和安卓 IOS的交互 例子式记录

    (function () { var u = navigator.userAgent; var isAndroid = u.indexOf('Android') > -1 || u.indexO ...

  2. Mysql 简介二

    Mysql 数据库引擎: 数据库引擎是用于存储.处理和保护数据的核心服务 Mysql支持的引擎一般有这几种: MyISAM Mysql 5.1版本之前默认的存储引擎,仅仅支持表锁,但查询速度较Inno ...

  3. openstack之虚拟机创建流程分析

    这篇博文静静的呆在草稿箱大半年了.假设不是由于某些原因被问到,以及由于忽略它而导致的损失,否则我也不知道什么时候会将它完毕.感谢这段时间经历的挫折,让我知道不足.希望你能给我更大的决心! 本文试图具体 ...

  4. axios封装http请求

    import axios from 'axios' const HTTP_TIMEOUT = 15000; export function httpPost(url, params = {},head ...

  5. GO语言学习(十四)Go 语言数组

    Go 语言数组 Go 语言提供了数组类型的数据结构. 数组是具有相同唯一类型的一组已编号且长度固定的数据项序列,这种类型可以是任意的原始类型例如整形.字符串或者自定义类型. 相对于去声明number0 ...

  6. 【前端统计图】echarts实现属性修改

    原图: 原代码: <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> < ...

  7. VC 常见问题百问

    http://www.cnblogs.com/cy163/archive/2006/06/19/429796.html 经典Vc书 Charles Petzold 的<Programming W ...

  8. 【例题 7-10 UVA - 11212】Editing a Book

    [链接] 我是链接,点我呀:) [题意] 在这里输入题意 [题解] 迭代加深搜. 很容易想到,最多只要搜8层就可以得到答案了 ->最多8下肯定可以还原. 则枚举一下最大层数.然后做个深搜就好. ...

  9. C++ 中的异或操作^

    好好的利用异或能够产生奇妙的效果. 异或运算的性质: 不论什么一个数字异或它自己都等于0.也就是说.假设我们从头到尾依次异或数组中的每个数字,那么终于的结果刚好是那个仅仅出现一次的数字.由于那些出现两 ...

  10. Android 设置背景透明度

    一些时候,我们须要为UI页面设置背景色,例如以下图所看到的: 上图已注: 背景颜色为#000000,透明度为40%: 那么.怎样在代码中表示呢? 首先须要了解: 颜色和不透明度 (alpha) 值以十 ...