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 原型模式创建对象

    例子: class Test { constructor(val) { this.val = val } walk() { console.log(this) console.log('walk') ...

  2. 《WPF》Expander控件简单美化

    示例图: Expander控件功能很常见, 一般用于系统左侧的菜单收缩面板. 1.主要的组成 一个头部(header) 和 一个 内容(content) 组成. <Expander Expand ...

  3. Android开机自动运行APP——BroadcastReceiver

    前言: 有些时候,应用需要在开机时就自动运行,例如某个自动从网上更新内容的后台service.怎样实现开机自动运行的应用?在撰写本文时,联想到高焕堂先生以“Don't call me, I'll ca ...

  4. subline Text3 安装及汉化

    因为自己的subline 有问题  所以决心重新改一下了. 三步: http://www.sublimetext.com/3      官网下载subline3 https://www.imjeff. ...

  5. JS实现拖拽小案例

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  6. [D3] Add image to the node

    We can create node with 'g' container, then append 'image' to the nodes. // Create container for the ...

  7. 好记性不如烂笔头——double

    两个数据转换成double型做差,会出现误差,转换成Decimal就OK了.

  8. 页面事件(Init,Load,PreRender)执行顺序

    简介 对由 Microsoft® Internet 信息服务 (IIS) 处理的 Microsoft® ASP.NET 页面的每个请求都会被移交到 ASP.NET HTTP 管道.HTTP 管道由一系 ...

  9. UVA10006 - Carmichael Numbers(筛选构造素数表+高速幂)

    UVA10006 - Carmichael Numbers(筛选构造素数表+高速幂) 题目链接 题目大意:假设有一个合数.然后它满足随意大于1小于n的整数a, 满足a^n%n = a;这种合数叫做Ca ...

  10. 使用MongoDb连接数据库服务器

    链接MongoDb数据库服务器的字符串格式: mongodb://[username:password@]host1[:port1][,host2[:port2],...[,hostN[:portN] ...