ngrx apps in depth
TRANSCRIPT
![Page 1: NGRX Apps in Depth](https://reader031.vdocuments.mx/reader031/viewer/2022030317/5a6511f07f8b9aa6218b4a25/html5/thumbnails/1.jpg)
June 15, 2017IPT – Intellectual
Products & Technologies
NGRX Apps in Depth – RxJS,
Reselect, Router, IndexedDB,
@Effects
Trayan [email protected]://iproduct.org
Copyright © 2003-2017 IPT - Intellectual Products & Technologies
![Page 2: NGRX Apps in Depth](https://reader031.vdocuments.mx/reader031/viewer/2022030317/5a6511f07f8b9aa6218b4a25/html5/thumbnails/2.jpg)
IPT - Intellectual Products & Technologies
2
Since 2003 we provide trainings and share skills in JS/ TypeScript/ Node/ Express/ Socket.IO/ NoSQL/ Angular/ React / Java SE/ EE/ Web/ REST SOA:
Node.js + Express/ hapi + React.js + Redux + GraphQL
Angular + TypeScript + Redux (ngrx)
Java EE6/7, Spring, JSF, Portals: Liferay, GateIn
Reactive IoT with Reactor / RxJava / RxJS
SOA & Distributed Hypermedia APIs (REST)
Domain Driven Design & Reactive Microservices
![Page 3: NGRX Apps in Depth](https://reader031.vdocuments.mx/reader031/viewer/2022030317/5a6511f07f8b9aa6218b4a25/html5/thumbnails/3.jpg)
3
NGRX Apps in Depth
State management, event sourcing, DDD, reactive programming, and stream based service architectures
Flux, Redux & NGRX: Reactive Extensions for Angular
Composing NGRX Reducers, Selectors & Middleware
Computing derived data (memoization): Reselect, RxJS
Observable (hot) streams of async actions – isolating side effects using @Effect & RxJS reactive transforms
NGRX-Router integration, Material Design, PrimeNG
Normalization/denormalization, local data – IndexedDB
Example app – code structure, lazy loading, etc.
![Page 4: NGRX Apps in Depth](https://reader031.vdocuments.mx/reader031/viewer/2022030317/5a6511f07f8b9aa6218b4a25/html5/thumbnails/4.jpg)
Where to Find the Demo Code?
4
Angular and NGRX demos are available @GitHub:
https://github.com/iproduct/course-angular
ipt-knowledge-manager – NGRX, Reselect, RxJS @Effects, modules lazy loading, AOT
angular2-change-detection-demos – modified from https://github.com/thoughtram/angular2-change-detection-demos
ngrx-example-app – NGRX official demo from https://github.com/ngrx/example-app, IndexedDB
![Page 5: NGRX Apps in Depth](https://reader031.vdocuments.mx/reader031/viewer/2022030317/5a6511f07f8b9aa6218b4a25/html5/thumbnails/5.jpg)
Data / Event / Message Streams
5
“Conceptually, a stream is a (potentially never-ending) flow of data records, and a transformation is an operation that takes one or more streams as input, and produces one or more output streams as a result.”
Apache Flink: Dataflow Programming Model
![Page 6: NGRX Apps in Depth](https://reader031.vdocuments.mx/reader031/viewer/2022030317/5a6511f07f8b9aa6218b4a25/html5/thumbnails/6.jpg)
Data Stream Programming
6
The idea of abstracting logic from execution is hardly new -- it was the dream of SOA. And the recent emergence of microservices and containers shows that the dream still lives on.
For developers, the question is whether they want to learn yet one more layer of abstraction to their coding.
… there's the elusive promise of a common API to streaming engines that in theory should let you mix and match, or swap in and swap out.
Tony Baer (Ovum) @ ZDNet - Apache Beam and Spark: New comopetition for squashing the Lambda Architecture?
![Page 7: NGRX Apps in Depth](https://reader031.vdocuments.mx/reader031/viewer/2022030317/5a6511f07f8b9aa6218b4a25/html5/thumbnails/7.jpg)
Listen to Quark:
7
“Good things come in small packages”
Quark – Star Trek DS9 character
https://en.wikipedia.org/w/index.php?curid=12544179, Star Trek: Deep Space Nine, "Emissary", Fair use
![Page 8: NGRX Apps in Depth](https://reader031.vdocuments.mx/reader031/viewer/2022030317/5a6511f07f8b9aa6218b4a25/html5/thumbnails/8.jpg)
Lambda Architecture - I
8
https://commons.wikimedia.org/w/index.php?curid=34963986, By Textractor - Own work, CC BY-SA 4
![Page 9: NGRX Apps in Depth](https://reader031.vdocuments.mx/reader031/viewer/2022030317/5a6511f07f8b9aa6218b4a25/html5/thumbnails/9.jpg)
Lambda Architecture - II
9
https://commons.wikimedia.org/w/index.php?curid=34963987, By Textractor - Own work, CC BY-SA 4
![Page 10: NGRX Apps in Depth](https://reader031.vdocuments.mx/reader031/viewer/2022030317/5a6511f07f8b9aa6218b4a25/html5/thumbnails/10.jpg)
Lambda Architecture - III
10
Data-processing architecture designed to handle massive quantities of data by using both batch- and stream-processing methods
Balances latency, throughput, fault-tolerance, big data, real-time analytics, mitigates the latencies of map-reduce
Data model with an append-only, immutable data source that serves as a system of record
Ingesting and processing timestamped events that are appended to existing events. State is determined from the natural time-based ordering of the data.
![Page 11: NGRX Apps in Depth](https://reader031.vdocuments.mx/reader031/viewer/2022030317/5a6511f07f8b9aa6218b4a25/html5/thumbnails/11.jpg)
Druid Distributed Data Store
11
https://commons.wikimedia.org/w/index.php?curid=33899448 By Fangjin Yang - sent to me personally, GFDL
Apache ZooKeeper
MySQL / PostgreSQL
HDFS / Amazon S3
![Page 12: NGRX Apps in Depth](https://reader031.vdocuments.mx/reader031/viewer/2022030317/5a6511f07f8b9aa6218b4a25/html5/thumbnails/12.jpg)
Lambda Architecture: Projects - I
12
![Page 13: NGRX Apps in Depth](https://reader031.vdocuments.mx/reader031/viewer/2022030317/5a6511f07f8b9aa6218b4a25/html5/thumbnails/13.jpg)
Direct Acyclic Graphs - DAG
13
![Page 14: NGRX Apps in Depth](https://reader031.vdocuments.mx/reader031/viewer/2022030317/5a6511f07f8b9aa6218b4a25/html5/thumbnails/14.jpg)
14
Performance is about 2 things:– Throughput – units per second, and – Latency – response time, responsiveness - especially
important from end user perspective (front-end)
Real-time – time constraint from input to response regardless of system load.
Hard real-time system if this constraint is not honored then a total system failure can occur.
Soft real-time system – low latency response with little deviation in response time
100 nano-seconds to 100 milli-seconds. [Peter Lawrey]
What High Performance Means?
![Page 15: NGRX Apps in Depth](https://reader031.vdocuments.mx/reader031/viewer/2022030317/5a6511f07f8b9aa6218b4a25/html5/thumbnails/15.jpg)
Synchronous vs. Asynchronous IO
15
DB
Synchronous
A
A
B
B
DB
Asynchronous
A
B
C
D
A
B
C
D
![Page 16: NGRX Apps in Depth](https://reader031.vdocuments.mx/reader031/viewer/2022030317/5a6511f07f8b9aa6218b4a25/html5/thumbnails/16.jpg)
Tracking Complexity
16
We need tools to cope with all that complexity inherent in real world applications.
Simple solutions are needed – cope with problems through divide and concur on different levels of abstraction:
Domain Driven Design (DDD) – back to basics: domain objects, data and logic.
Described by Eric Evans in his book: Domain Driven Design: Tackling Complexity in the Heart of Software, 2004
![Page 17: NGRX Apps in Depth](https://reader031.vdocuments.mx/reader031/viewer/2022030317/5a6511f07f8b9aa6218b4a25/html5/thumbnails/17.jpg)
Microservices and DDD
17
Main concepts:
Entities, value objects and modules
Aggregates and Aggregate Roots:
value < entity < aggregate < module < BC
Aggregate Roots are exposed as Open Host Services
Hexagonal architecture :
OUTSIDE <-> transformer <-> ( application <-> domain )
![Page 18: NGRX Apps in Depth](https://reader031.vdocuments.mx/reader031/viewer/2022030317/5a6511f07f8b9aa6218b4a25/html5/thumbnails/18.jpg)
Imperative and Reactive
18
We live in a Connected Universe
... there is hypothesis that all the things in the Universe are intimately connected, and you can not change a bit without changing all.
Action – Reaction principle is the essence of how Universe behaves.
![Page 19: NGRX Apps in Depth](https://reader031.vdocuments.mx/reader031/viewer/2022030317/5a6511f07f8b9aa6218b4a25/html5/thumbnails/19.jpg)
Imperative and Reactive
Reactive Programming: using static or dynamic data flows and propagation of change
Example: a := b + c
Functional Programming: evaluation of mathematical functions, ➢ Avoids changing-state and mutable data, declarative
programming➢ Side effects free => much easier to understand and
predict the program behavior. Example: Observable.from(['Reactive', 'Extensions','JS'])
.take(2).map(s => `${s}: on ${new Date()}`) .subscribe(s => console.log(s));
![Page 20: NGRX Apps in Depth](https://reader031.vdocuments.mx/reader031/viewer/2022030317/5a6511f07f8b9aa6218b4a25/html5/thumbnails/20.jpg)
Functional Reactive (FRP)
20
According to Connal Elliot's (ground-breaking paper @Conference on Functional Programming, 1997), FRP is: (a) Denotative (Compositional): Observables can be
composed with higher-order combinators (b) Temporally continuous (Lazy): Observables do
not start emitting data until an Observer has subscribed
![Page 22: NGRX Apps in Depth](https://reader031.vdocuments.mx/reader031/viewer/2022030317/5a6511f07f8b9aa6218b4a25/html5/thumbnails/22.jpg)
22
Message Driven – asynchronous message-passing allows to establish a boundary between components that ensures loose coupling, isolation, location transparency, and provides the means to delegate errors as messages.
[Reactive Manifesto]
Scalable, Massively Concurrent
![Page 23: NGRX Apps in Depth](https://reader031.vdocuments.mx/reader031/viewer/2022030317/5a6511f07f8b9aa6218b4a25/html5/thumbnails/23.jpg)
Reactive Programming Specs
23
Reactive Streams Specification [http://www.reactive-streams.org/]
ES7 Observable Spec (implemented by RxJS 5) [https://github.com/tc39/proposal-observable]
Open source polyglot project ReactiveX (Reactive Extensions) [http://reactivex.io]:
Rx = Observables + LINQ + Schedulers :)Java: RxJava, JavaScript: RxJS, C#: Rx.NET, Scala: RxScala, Clojure: RxClojure, C++: RxCpp, Ruby: Rx.rb, Python: RxPY, Groovy: RxGroovy, JRuby: RxJRuby, Kotlin: RxKotlin ...
![Page 24: NGRX Apps in Depth](https://reader031.vdocuments.mx/reader031/viewer/2022030317/5a6511f07f8b9aa6218b4a25/html5/thumbnails/24.jpg)
Reactive Streams Spec.
24
Publisher – provider of potentially unbounded number of sequenced elements, according to Subscriber(s) demand.
Publisher.subscribe(Subscriber) => onSubscribe onNext* (onError | onComplete)?
Subscriber – calls Subscription.request(long) to receive notifications
Subscription – one-to-one Subscriber ↔ Publisher, request data and cancel demand (allow cleanup).
Processor = Subscriber + Publisher
![Page 25: NGRX Apps in Depth](https://reader031.vdocuments.mx/reader031/viewer/2022030317/5a6511f07f8b9aa6218b4a25/html5/thumbnails/25.jpg)
ES7 Observable Spec (RxJS 5)
25
interface Observable { constructor(subscriber : SubscriberFunction);
subscribe(observer : Observer) : Subscription;
subscribe(onNext : Function, onError? : Function, onComplete? : Function) : Subscription;
[Symbol.observable]() : Observable;
static of(...items) : Observable;
static from(iterableOrObservable) : Observable;}
interface Subscription { unsubscribe() : void; get closed() : Boolean;}
![Page 26: NGRX Apps in Depth](https://reader031.vdocuments.mx/reader031/viewer/2022030317/5a6511f07f8b9aa6218b4a25/html5/thumbnails/26.jpg)
26
RxJS – JS ReactiveX (Reactive Extensions)[http://reactivex.io, https://github.com/ReactiveX]
ReactiveX is a polyglot library for composing asynchronous event streams (observable sequences).
It extends the observer pattern by declarative composition of functional transformations on events streams (e.g. map-filter-reduce, etc.)
Abstracs away low-level concerns like concurrency, synchronization, and non-blocking I/O.
Follows the next - error - completed event flow
Allows natural implementation of Redux design pattern
Alternative (together with promises) for solving “callback hell” problem
![Page 27: NGRX Apps in Depth](https://reader031.vdocuments.mx/reader031/viewer/2022030317/5a6511f07f8b9aa6218b4a25/html5/thumbnails/27.jpg)
27
RxJS Resources
RxMarbles:
http://rxmarbles.com/
RxJS Coans:https://github.com/Reactive-Extensions/RxJSKoans
Learn RxJS:https://www.learnrxjs.io/
![Page 28: NGRX Apps in Depth](https://reader031.vdocuments.mx/reader031/viewer/2022030317/5a6511f07f8b9aa6218b4a25/html5/thumbnails/28.jpg)
Source: https://github.com/ReactiveX/rxjs/blob/master/doc/asset/marble-diagram-anatomy.svg, Apache v2
Anatomy of Rx Operator
![Page 29: NGRX Apps in Depth](https://reader031.vdocuments.mx/reader031/viewer/2022030317/5a6511f07f8b9aa6218b4a25/html5/thumbnails/29.jpg)
Example: combineLatest()
29
https://projectreactor.io/core/docs/api/, Apache Software License 2.0
![Page 30: NGRX Apps in Depth](https://reader031.vdocuments.mx/reader031/viewer/2022030317/5a6511f07f8b9aa6218b4a25/html5/thumbnails/30.jpg)
Example: switchMap()
30
http://reactivex.io/rxjs/class/es6/Observable.js~Observable.html, Apache Software License 2.0
![Page 31: NGRX Apps in Depth](https://reader031.vdocuments.mx/reader031/viewer/2022030317/5a6511f07f8b9aa6218b4a25/html5/thumbnails/31.jpg)
Hot and Cold Event Streams
31
PULL-based (Cold Event Streams) – Cold streams are streams that run their sequence when and if they are subscribed to. They present the sequence from the start to each subscriber.
PUSH-based (Hot Event Streams) – Hot streams emit values independent of individual subscriptions. They have their own timeline and events occur whether someone is listening or not. An example of this is mouse events. A mouse is generating events regardless of whether there is a subscription. When subscription is made observer receives current events as they happen.
![Page 32: NGRX Apps in Depth](https://reader031.vdocuments.mx/reader031/viewer/2022030317/5a6511f07f8b9aa6218b4a25/html5/thumbnails/32.jpg)
Converting Cold to Hot Stream
32
![Page 33: NGRX Apps in Depth](https://reader031.vdocuments.mx/reader031/viewer/2022030317/5a6511f07f8b9aa6218b4a25/html5/thumbnails/33.jpg)
Flux Design Pattern
Source: Flux in GitHub, https://github.com/facebook/flux, License: BSD 3-clause "New" License
![Page 34: NGRX Apps in Depth](https://reader031.vdocuments.mx/reader031/viewer/2022030317/5a6511f07f8b9aa6218b4a25/html5/thumbnails/34.jpg)
Linear flow:Source: @ngrx/store in GitHub, https://gist.github.com/btroncone/a6e4347326749f938510
Redux Design Pattern
![Page 35: NGRX Apps in Depth](https://reader031.vdocuments.mx/reader031/viewer/2022030317/5a6511f07f8b9aa6218b4a25/html5/thumbnails/35.jpg)
Source: RxJava 2 API documentation, http://reactivex.io/RxJava/2.x/javadoc/
Redux == Rx Scan Opearator
![Page 36: NGRX Apps in Depth](https://reader031.vdocuments.mx/reader031/viewer/2022030317/5a6511f07f8b9aa6218b4a25/html5/thumbnails/36.jpg)
Source: RxJS docs, https://github.com/ReactiveX/rxjs/blob/master/doc/tutorial/applications.md
Redux in Plain RxJS
import Immutable from 'immutable';import someObservable from './someObservable';import someOtherObservable from './someOtherObservable';
var initialState = { foo: 'bar' };
var state = Observable.merge( someObservable, someOtherObservable).scan((state, changeFn) => changeFn(state), Immutable.fromJS(initialState));
export default state;
![Page 37: NGRX Apps in Depth](https://reader031.vdocuments.mx/reader031/viewer/2022030317/5a6511f07f8b9aa6218b4a25/html5/thumbnails/37.jpg)
Source: RxJS docs, https://github.com/ReactiveX/rxjs/blob/master/doc/tutorial/applications.md
Redux in Plain RxJS
state.js:
import Immutable from 'immutable';import someObservable from './someObservable';import someOtherObservable from './someOtherObservable';
var initialState = { foo: 'bar' };
var state = Observable.merge( someObservable, someOtherObservable).scan((state, changeFn) => changeFn(state), Immutable.fromJS(initialState));
export default state;
![Page 38: NGRX Apps in Depth](https://reader031.vdocuments.mx/reader031/viewer/2022030317/5a6511f07f8b9aa6218b4a25/html5/thumbnails/38.jpg)
Redux in Plain RxJS
client.js:
import state from './state';
state.subscribe(state => { document.querySelector('#text').innerHTML = state.get('foo');});
Source: RxJS docs, https://github.com/ReactiveX/rxjs/blob/master/doc/tutorial/applications.md
![Page 39: NGRX Apps in Depth](https://reader031.vdocuments.mx/reader031/viewer/2022030317/5a6511f07f8b9aa6218b4a25/html5/thumbnails/39.jpg)
NGRX: Reactive Extensions for Angular
core – core functionality for the ngrx platform
store – RxJS powered state management for Angular applications, inspired by Redux
router-store – bindings to connect the Angular Router to @ngrx/store
effects – side effect model for @ngrx/store
db – RxJS powered IndexedDB for Angular apps
notify – Web Notifications powered by RxJS for Angular
store-devtools, store-log-monitor - dev tools, monitoring
example-app – example app showcasing ngrx platform
![Page 40: NGRX Apps in Depth](https://reader031.vdocuments.mx/reader031/viewer/2022030317/5a6511f07f8b9aa6218b4a25/html5/thumbnails/40.jpg)
Bootstraping NGRX App
In app.module.ts: @NgModule({ imports: [
StoreModule.provideStore(reducer),RouterStoreModule.connectRouter(),
StoreDevtoolsModule.instrumentOnlyWithExtension(), EffectsModule.run(BookEffects),
EffectsModule.run(CollectionEffects),DBModule.provideDB(schema),
... ] ...
![Page 41: NGRX Apps in Depth](https://reader031.vdocuments.mx/reader031/viewer/2022030317/5a6511f07f8b9aa6218b4a25/html5/thumbnails/41.jpg)
NGRX: Defining State & Reducers
in root.reducer.ts:
export interface RootState { router: fromRouter.RouterState; ui: fromUi.State; users: fromUsers.State; tests: fromTests.State;}
export const reducers: ReducersMap = { router: fromRouter.routerReducer, ui: fromUi.reducer, users: fromUsers.reducer, tests: fromTests.reducer};
![Page 42: NGRX Apps in Depth](https://reader031.vdocuments.mx/reader031/viewer/2022030317/5a6511f07f8b9aa6218b4a25/html5/thumbnails/42.jpg)
NGRX: Composing Root Reducer in root.reducer.ts:
const developmentReducer: ActionReducer<S> = compose(storeFreeze, combineReducers)(reducers);const productionReducer: ActionReducer<S> = combineReducers(reducers);
export function rootReducer(state: any, action: any) { if (environment.production) { return productionReducer(state, action) } else { return developmentReducer(state,action) }}
Store Middleware Composition
Needs to be statically importable by AOT
![Page 43: NGRX Apps in Depth](https://reader031.vdocuments.mx/reader031/viewer/2022030317/5a6511f07f8b9aa6218b4a25/html5/thumbnails/43.jpg)
NGRX Selectors
A selector function is a factory for mapping functions.
Returned function maps from larger state tree into a feature substate tree (destructing the larger state).
Selectors are used with the `select` ngrx Store operator. Following example shows selector selecting the `users` sub-state:
class ClientComponent { constructor(store$: Observable<State>) {
this.usersState$ = store$.select(getUsersState); } }
![Page 44: NGRX Apps in Depth](https://reader031.vdocuments.mx/reader031/viewer/2022030317/5a6511f07f8b9aa6218b4a25/html5/thumbnails/44.jpg)
Composing User Selectors in users/user.selectors.ts: // User state selectorsexport const getEntities = (state: State) => state.entities;export const getIds = (state: State) => state.ids;export const getAll = createSelector(getEntities, getIds, (entities, ids)=>{ return ids.map(id => entities[id]); });
// Root state selectorsexport const getUsersState = (state: RootState) => state.users;export const getUsers = createSelector(getUsersState, getAll);
![Page 45: NGRX Apps in Depth](https://reader031.vdocuments.mx/reader031/viewer/2022030317/5a6511f07f8b9aa6218b4a25/html5/thumbnails/45.jpg)
Using Reselect in users/user.selectors.ts: // User state selectorsexport const getEntities = (state: State) => state.entities;export const getIds = (state: State) => state.ids;export const getAll = createSelector(getEntities, getIds, (entities, ids)=>{ return ids.map(id => entities[id]); });
// Root state selectorsexport const getUsersState = (state: RootState) => state.users;export const getUsers = createSelector(getUsersState, getAll);
![Page 46: NGRX Apps in Depth](https://reader031.vdocuments.mx/reader031/viewer/2022030317/5a6511f07f8b9aa6218b4a25/html5/thumbnails/46.jpg)
Computing Derived Data: Reselect
Selectors can compute derived data, allowing Redux to store the minimal possible state.
Selectors are efficient. A selector is not recomputed unless one of its arguments change.
Selectors are composable. They can be used as input to other selectors.
Works correctly only when combined with immutability.
![Page 47: NGRX Apps in Depth](https://reader031.vdocuments.mx/reader031/viewer/2022030317/5a6511f07f8b9aa6218b4a25/html5/thumbnails/47.jpg)
Computing Derived Data: Reselectimport { createSelector } from 'reselect'const getVisibilityFilter = (state) => state.visibilityFilterconst getTodos = (state) => state.todosexport const getVisibleTodos = createSelector( [ getVisibilityFilter, getTodos ], (visibilityFilter, todos) => { switch (visibilityFilter) { case 'SHOW_ALL': return todos case 'SHOW_COMPLETED': return todos.filter(t => t.completed) case 'SHOW_ACTIVE': return todos.filter(t => !t.completed)}});
![Page 48: NGRX Apps in Depth](https://reader031.vdocuments.mx/reader031/viewer/2022030317/5a6511f07f8b9aa6218b4a25/html5/thumbnails/48.jpg)
Can You Spot the Problem Here?const isFirstTodoCompleteSelector = createSelector(state => state.todos[0], todo => todo && todo.completed)
export default function todos(state = initState, action) { switch (action.type) { case COMPLETE_ALL: const allMarked = state.every(todo => todo.completed) return state.map(todo => { todo.completed = !allMarked return todo }) default: return state}}
![Page 49: NGRX Apps in Depth](https://reader031.vdocuments.mx/reader031/viewer/2022030317/5a6511f07f8b9aa6218b4a25/html5/thumbnails/49.jpg)
Can We Memoize without Reselect?
In users/components/user-list.component.ts:
public ngOnInit() { this.store.dispatch(this.userActions.loadUsers()); this.subscription = this.selectedId$ .filter(id => !!id) .distinctUntilChanged() .subscribe(id => this.store.dispatch( go(['users', id])));
![Page 50: NGRX Apps in Depth](https://reader031.vdocuments.mx/reader031/viewer/2022030317/5a6511f07f8b9aa6218b4a25/html5/thumbnails/50.jpg)
Router Integration, MD, PrimeNG
![Page 51: NGRX Apps in Depth](https://reader031.vdocuments.mx/reader031/viewer/2022030317/5a6511f07f8b9aa6218b4a25/html5/thumbnails/51.jpg)
State Normalization / Denormalization [http://redux.js.org/docs/recipes/reducers/NormalizingStateShape.html]
When a piece of data is duplicated in several places, it becomes harder to make sure that it is updated appropriately
Nested data means that the corresponding reducer logic has to be more nested or more complex. In particular, trying to update a deeply nested field can become very ugly very fast.
Since immutable data updates require all ancestors in the state tree to be copied and updated as well, an update to a deeply nested data object could force totally unrelated UI components to re-render even if the data they're displaying hasn't actually changed.
![Page 52: NGRX Apps in Depth](https://reader031.vdocuments.mx/reader031/viewer/2022030317/5a6511f07f8b9aa6218b4a25/html5/thumbnails/52.jpg)
Example: Users State Normalization
export interface State { ids: IdentityType[]; entities: { [id: string]: User }; selectedUserId: IdentityType | null; loading: boolean;};export const initialState: State = { ids: [], entities: {}, selectedUserId: null, loading: false};export function usersReducer(state = initialState,
action: Action): State { switch (action.type) { ...
![Page 53: NGRX Apps in Depth](https://reader031.vdocuments.mx/reader031/viewer/2022030317/5a6511f07f8b9aa6218b4a25/html5/thumbnails/53.jpg)
IndexedDB IndexedDB is a low-level API for client-side storage of
significant amounts of structured data (key-value pairs), including files/blobs.
API uses indexes to enable high-performance searches of this data. Web Storage - useful for smaller data.
IndexedDB is built on a transactional database model – everything you do in IndexedDB always happens in the context of a transaction.
The IndexedDB API is mostly asynchronous – you have to pass a callback function.
IndexedDB uses DOM events to notify you when results are available - type prop ("success" or "error").
![Page 54: NGRX Apps in Depth](https://reader031.vdocuments.mx/reader031/viewer/2022030317/5a6511f07f8b9aa6218b4a25/html5/thumbnails/54.jpg)
Example: @Effect and IndexedDBconstructor(private actions$: Actions, private db: Database) { }@Effect({ dispatch: false }) openDB$: Observable<any> = defer(() => { return this.db.open('books_app'); });@Effect() loadCollection$: Observable<Action> = this.actions$ .ofType(collection.LOAD) .startWith(new collection.LoadAction()) .switchMap(() => this.db.query('books').toArray() .map((books: Book[]) => new collection.LoadSuccessAction(books)) .catch(error => of( new collection.LoadFailAction(error))) );
![Page 55: NGRX Apps in Depth](https://reader031.vdocuments.mx/reader031/viewer/2022030317/5a6511f07f8b9aa6218b4a25/html5/thumbnails/55.jpg)
@Effect() addBookToCollection$: Observable<Action> = this.actions$ .ofType(collection.ADD_BOOK) .map((action: collection.AddBookAction) => action.payload) .mergeMap(book => this.db.insert('books', [ book ]) .map(() => new collection.AddBookSuccessAction(book)) .catch(() => of( new collection.AddBookFailAction(book))) );
Example: @Effect and IndexedDB
![Page 56: NGRX Apps in Depth](https://reader031.vdocuments.mx/reader031/viewer/2022030317/5a6511f07f8b9aa6218b4a25/html5/thumbnails/56.jpg)
@Effect()
removeBookFromCollection$: Observable<Action> = this.actions$ .ofType(collection.REMOVE_BOOK) .map((action: collection.RemoveBookAction) => action.payload) .mergeMap(book => this.db.executeWrite('books', 'delete', [book.id]) .map(() => new collection.RemoveBookSuccessAction(book)) .catch(() => of( new collection.RemoveBookFailAction(book))) );
Example: @Effect and IndexedDB
![Page 57: NGRX Apps in Depth](https://reader031.vdocuments.mx/reader031/viewer/2022030317/5a6511f07f8b9aa6218b4a25/html5/thumbnails/57.jpg)
export interface RootState { ui: fromUi.State; router: fromRouter.RouterState;}export interface ReducersMap { [key: string]: ActionReducer<any>; }const reducers: ReducersMap = { ui: fromUi.reducer, router: fromRouter.routerReducer};const devProdReducers: ReducersMap = { developmentReducer: compose(storeFreeze, combineReducers)(reducers), productionReducer: combineReducers(reducers) }
How to Lazy Load Reducers? - I
![Page 58: NGRX Apps in Depth](https://reader031.vdocuments.mx/reader031/viewer/2022030317/5a6511f07f8b9aa6218b4a25/html5/thumbnails/58.jpg)
export function addReducer<S>(name: string, reducer: ActionReducer<S>): void { reducers[name] = reducer; devProdReducers['developmentReducer'] = compose(storeFreeze, combineReducers)(reducers); devProdReducers['productionReducer'] = combineReducers(reducers);}export function rootReducer(state: any, action: any) { if (environment.production) { return devProdReducers.productionReducer(state, action) } else { return devProdReducers.developmentReducer(state,action) }}
How to Lazy Load Reducers? - II
This works happily with AOT!
![Page 59: NGRX Apps in Depth](https://reader031.vdocuments.mx/reader031/viewer/2022030317/5a6511f07f8b9aa6218b4a25/html5/thumbnails/59.jpg)
in lazy loaded module (users/user.module.ts):
@NgModule({ ... })export class UserModule { constructor() { addReducer<UserState>('users', usersReducer); }}export interface RootState extends OldRootState { users: UserState;}
Then everywhere in lazy loaded module import augmented RootState from that lazy loaded module (from users/user.module.ts, not from root.reducer.ts).
Adding New Lazy Loaded Reducer
![Page 60: NGRX Apps in Depth](https://reader031.vdocuments.mx/reader031/viewer/2022030317/5a6511f07f8b9aa6218b4a25/html5/thumbnails/60.jpg)
Where to Find the Demo Code?
60
Angular and NGRX demos are available @GitHub:
https://github.com/iproduct/course-angular
ipt-knowledge-manager – NGRX, Reselect, RxJS @Effects, modules lazy loading, AOT
angular2-change-detection-demos – modified from https://github.com/thoughtram/angular2-change-detection-demos
ngrx-example-app – NGRX official demo from https://github.com/ngrx/example-app, IndexedDB
![Page 61: NGRX Apps in Depth](https://reader031.vdocuments.mx/reader031/viewer/2022030317/5a6511f07f8b9aa6218b4a25/html5/thumbnails/61.jpg)
Thank’s for Your Attention!
61
Trayan Iliev
CEO of IPT – Intellectual Products & Technologies
http://iproduct.org/
http://robolearn.org/
https://github.com/iproduct
https://twitter.com/trayaniliev
https://www.facebook.com/IPT.EACAD
https://plus.google.com/+IproductOrg