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. 在手机中预置联系人/Service Number

    代码分为两部分: Part One 将预置的联系人插入到数据库中: Part Two 保证预置联系人仅仅读,无法被编辑删除(在三个地方屏蔽对预置联系人进行编辑处理:联系人详情界面.联系人多选界面.新建 ...

  2. 报错 关于python的x和y不等长

    ValueError: shape mismatch: objects cannot be broadcast to a single shape 这个错误可能是因为传入的两个参数数据长度不一样,比如 ...

  3. loadrunner监控linux之linux下安装rpc

    安装和配置rpc服务 说明:rpc服务需rsh的支持,一般情况下rsh已安装.通过rpm -qa rsh命令查看. 下载rpc.rstatd-4.0.1.tar.gz,可先下载到window下,通过f ...

  4. Docker 部署Dotnet Core MVC项目

    原文:Docker 部署Dotnet Core MVC项目 1.dotnet core创建项目 dotnet new mvc -o myweb cd myweb 然后就是业务代码的编辑,增删改查乱七八 ...

  5. Android 解决RecyclerView删除Item导致位置错乱的问题

    RecyclerView的刷新分为内容变化和结构变化,结构变化比如remove和insert等并不会导致viewholder的更新,所以有时候我们使用 notifyItemRemoved(positi ...

  6. JS学习笔记 - fgm练习 - 多按钮控制同个div属性

    总结: 1. 注意body里的结构安排,全部装在大div,避免多次设置不同部分居中. 2. 一排按钮居中:装在大div里,text-align: center; 3. 把相同的部分封装成函数,即 同个 ...

  7. 微服务实战(一):微服务架构的优势与不足 - DockOne.io

    原文:微服务实战(一):微服务架构的优势与不足 - DockOne.io [编者的话]本文来自Nginx官方博客,是微服务系列文章的第一篇,主要探讨了传统的单体式应用的不足,以及微服务架构的优势与挑战 ...

  8. 如何获取用户的地理位置-浏览器地理位置(Geolocation)API 简介

    如何获取用户的地理位置-浏览器地理位置(Geolocation)API 简介 一.总结 一句话总结:Geolocation API(地理位置应用程序接口)提供了一个可以准确知道浏览器用户当前位置的方法 ...

  9. amazeui学习笔记--js插件(UI增强2)--按钮交互Button

    amazeui学习笔记--js插件(UI增强2)--按钮交互Button 一.总结 1.按钮loading状态: <button type="button" class=&q ...

  10. zoj 2724 Windows Message Queue 优先队列

    http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemId=1724 题目大意: 给出两种操作,GET要求取出当前队首的元素,而PUT会输入名 ...