SlideShare une entreprise Scribd logo
1  sur  53
Télécharger pour lire hors ligne
NG2 & NgRx/Store:
Oren Farhi @Orizens
hi!
I AM Oren Farhi
Senior Javascript Engineer
Freelance Javascript Consultant & Tutor
You can find me at:
orizens.com
github.com/orizens
@orizens
There’s Gotta Be Something Better
Redux for Angular 2 with NgRx/Store
- Problems of State Management
- What is NgRx/Store
- Usecase App - Echoes Player
NgRx/Store In Echoes Player Agenda
Problems With
State Management
The State Of The App?
◦ Where?
◦ Share
Current State Of The App
UI ⇔ Model
Solution: ngrx/store (benefits)
1. App State is Predictable
2. Separate Logics From UI
3. Optimization in Performance
4. Easy To Test
5. Time Travel (logs)
6. Route & State
7. Promotes Stateless Components
Ngrx/Store
State Management Made Easy
Example App: Echoes Player - http://echotu.be
Store
Mother Of All States
Store is an observable “DB”
Store
{ Data }
{ Object }
[ Array ]
number
string
{ Data }
{ Data }
{ Data }
Store - json object...
bootstrap(App, [
provideStore({ videos: videosReducer })
]);
Reducers - CRUD the Store with Pure Functions (Observable)
const videos = function(state = [], action) => {
switch (action.type) {
case 'ADD_VIDEO':
return state.concat( action.payload );
default:
return state;
}
}
Reducers - CRUD the Store with Pure Functions (Observable)
let sum = [1,2,3]
sum.reduce(
(result, value) => result + value,
0
);
Action - dispatch an update to State through Reducers
addVideo(media) {
this.store.dispatch({
type: ‘ADD_VIDEO’,
payload: media
});
}
Subscribe And Observe - data projection, slice store’s data
@Component({ selector: ‘youtube-player’ })
constructor (store) {
this.player$ = store.select(store => store.player);
this.player$.subscribe(player => {
this.isFullscreen = player.isFullscreen
});
}
Subscribe - data projection - listen with Observable
@Component({ selector: ‘youtube-player’ })
constructor (store) {
this.player$ = store.select(store => store.player);
this.player$.subscribe(player => {
this.isFullscreen = player.isFullscreen
});
}
Subscribe And Observe - data projection, slice store’s data
let initialPlayerState = {
mediaId: { videoId: 'NONE' },
media: {
snippet: { title: 'No Media Yet' }
},
showPlayer: true,
playerState: 0,
isFullscreen: false
}
UI Subscribe - “async” pipe - data projection to view
<section class="player">
<player-controls
[player]="player$ | async"
(action)="handleControlAction($event)"
></player-controls>
</section>
let tempObv = player$.subscribe(player => this.player = player);
tempObv.unsubscribe(); // when view is destroyed
One Way Data Flow
Component
Reducer
Store
Action
NgRx/Store in Echoes Player
Store & The Youtube Videos Component
Store In Echoes Player
export interface EchoesState {
videos: EchoesVideos;
player: YoutubePlayerState;
nowPlaylist: YoutubeMediaPlaylist;
user: UserProfile;
search: PlayerSearch;
}
Youtube Videos - SMART Component
<youtube-videos>
Youtube Videos - 2 Stateless Components (DUMB)
<youtube-videos>
<youtube-list>
<player-search>
Youtube Videos Component (SMART)
@Component({
selector: 'youtube-videos',
directives: [ PlayerSearchComponent, YoutubeList],
template: `
<player-search
[query]="search$ | async"
(change)="resetPageToken()"
(search)="search($event)"
></player-search>
<youtube-list
[list]="videos$ | async"
(play)="playSelectedVideo($event)"
(queue)="queueSelectedVideo($event)"
></youtube-list>`
})
export class YoutubeVideos implements OnInit {}
Youtube Videos Component (SMART)
@Component({
selector: 'youtube-videos',
directives: [ PlayerSearchComponent, YoutubeList],
template: `
<player-search
[query]="search$ | async"
(change)="resetPageToken()"
(search)="search($event)"
></player-search>
<youtube-list
[list]="videos$ | async"
(play)="playSelectedVideo($event)"
(queue)="queueSelectedVideo($event)"
></youtube-list>`
})
export class YoutubeVideos implements OnInit {}
Performance Boost For Components
@Component({
selector: 'youtube-list',
template: `
<youtube-media
*ngFor="let media of list"
[media]="media"
(play)="playSelectedVideo(media)"
(queue)="queueSelectedVideo(media)"
(add)="addVideo(media)">
</youtube-media>
`,
directives: [NgFor, YoutubeMedia ],
changeDetection: ChangeDetectionStrategy.OnPush
})
export class YoutubeList {
@Input() list: Array<any>;
}
Youtube Videos Component (SMART)
@Component({
selector: 'youtube-videos',
directives: [ PlayerSearchComponent, YoutubeList],
template: `
<player-search
[query]="search$ | async"
(change)="resetPageToken()"
(search)="search($event)"
></player-search>
<youtube-list
[list]="videos$ | async"
(play)="playSelectedVideo($event)"
(queue)="queueSelectedVideo($event)"
></youtube-list>`
})
export class YoutubeVideos implements OnInit {}
Youtube Videos - Connecting to Store
export class YoutubeVideos implements OnInit {
videos$: Observable<EchoesVideos>;
search$: Observable<PlayerSearch>;
constructor(
private youtubeSearch: YoutubeSearch,
private nowPlaylistService: NowPlaylistService,
private store: Store<EchoesState>,
public youtubePlayer: YoutubePlayerService) {
this.videos$ = store.select(state => state.videos);
this.search$ = store.select(state => state.search);
}
}
Youtube Videos - Connecting to Store
export class YoutubeVideos implements OnInit {
videos$: Observable<EchoesVideos>;
search$: Observable<PlayerSearch>;
constructor(
private youtubeSearch: YoutubeSearch,
private nowPlaylistService: NowPlaylistService,
private store: Store<EchoesState>,
public youtubePlayer: YoutubePlayerService) {
this.videos$ = store.select(state => state.videos);
this.search$ = store.select(state => state.search);
}
}
Updating the Store
@Component({
selector: 'youtube-videos',
directives: [ PlayerSearchComponent, YoutubeList],
template: `
<player-search
[query]="search$ | async"
(change)="resetPageToken()"
(search)="search($event)"
></player-search>
<youtube-list
[list]="videos$ | async"
(play)="playSelectedVideo($event)"
(queue)="queueSelectedVideo($event)"
></youtube-list>`
})
export class YoutubeVideos implements OnInit {}
Youtube Videos Component
Interaction with store services:
- YoutubeSearch
- YoutubePlayer
- NowPlaylist
Youtube Videos - Updating The Store
export class YoutubeVideos implements OnInit {
videos$: Observable<EchoesVideos>;
playerSearch$: Observable<PlayerSearch>;
constructor(){ ... }
search (query: string) {
if (query.length) {
this.youtubeSearch.search(query, false);
}
}
queueSelectedVideo (media: GoogleApiYouTubeSearchResource) {
return this.nowPlaylistService.queueVideo(media.id.videoId);
}
}
Youtube Videos - Updating The Store
export class YoutubeVideos implements OnInit {
videos$: Observable<EchoesVideos>;
playerSearch$: Observable<PlayerSearch>;
constructor(){ ... }
search (query: string) {
if (query.length) {
this.youtubeSearch.search(query, false);
}
}
queueSelectedVideo (media: GoogleApiYouTubeSearchResource) {
return this.nowPlaylistService.queueVideo(media.id.videoId);
}
}
Services - dispatch to Store
@Injectable()
export class NowPlaylistService {
constructor(public store: Store<EchoesState>) {
this.playlist$ = this.store.select(state => state.nowPlaylist);
}
queueVideo (mediaId: string) {
return this.youtubeVideosInfo.api
.list(mediaId).then(response => {
this.store.dispatch({
type: QUEUE, //- const imported from reducer
payload: response.items[0]
});
return response.items[0];
});
}
}
NowPlaylist Reducer
let initialState = {
videos: [],
index: '',
filter: ''
}
export const nowPlaylist = (state = initialState, action) => {
switch (action.type) {
case NowPlaylistActions.QUEUE:
return Object.assign(
);
default:
return state;
}
NowPlaylist Reducer
let initialState = {
videos: [],
index: '',
filter: ''
}
export const nowPlaylist = (state = initialState, action) => {
switch (action.type) {
case NowPlaylistActions.QUEUE:
return Object.assign({}, state, {
videos: addMedia(state.videos, action.payload)
});
default:
return state;
}
Services - dispatch to Store
@Injectable()
export class NowPlaylistService {
constructor(public store: Store<EchoesState>) {
this.playlist$ = this.store.select(state => state.nowPlaylist);
}
queueVideo (mediaId: string) {
return this.youtubeVideosInfo.api
.list(mediaId).then(response => {
this.store.dispatch({
type: QUEUE, //- const imported from reducer
payload: response.items[0]
});
return response.items[0];
});
}
}
Ngrx/effects
Side effects of Actions
Side Effects for Queue Video
@Injectable()
export class NowPlaylistEffects {
constructor(
store$,
nowPlaylistActions
youtubeVideosInfo
){}
@Effect() queueVideoReady$ = this.store$
.whenAction(NowPlaylistActions.QUEUE_LOAD_VIDEO)
.map<GoogleApiYouTubeSearchResource>(toPayload)
.switchMap(media => this.youtubeVideosInfo.fetchVideoData(media.id.
videoId)
.map(media => this.nowPlaylistActions.queueVideo(media))
.catch(() => Observable.of(this.nowPlaylistActions.queueFailed(media)))
);
}
Testing Reducers
Testing now playlist
Loading the tested objects
import {
it,
inject,
async,
describe,
expect
} from '@angular/core/testing';
import { nowPlaylist, NowPlaylistActions } from './now-playlist';
import { YoutubeMediaItemsMock } from './mocks/youtube.media.
items';
Spec - select a video in now playlist
it('should select the chosen video', () => {
const state = { index: '', videos: [...YoutubeMediaItemsMock], filter: '' };
const actual = nowPlaylist(state, {
type: NowPlaylistActions.SELECT,
payload: YoutubeMediaItemsMock[0]
});
const expected = YoutubeMediaItemsMock[0];
expect(actual.index).toBe(expected.id);
});
Spec - set initial state
it('should select the chosen video', () => {
const state = { index: '', videos: [...YoutubeMediaItemsMock], filter: '' };
const actual = nowPlaylist(state, {
type: NowPlaylistActions.SELECT,
payload: YoutubeMediaItemsMock[0]
});
const expected = YoutubeMediaItemsMock[0];
expect(actual.index).toBe(expected.id);
});
Spec - select a video in now playlist
it('should select the chosen video', () => {
const state = { index: '', videos: [...YoutubeMediaItemsMock], filter: '' };
const actual = nowPlaylist(state, {
type: NowPlaylistActions.SELECT,
payload: YoutubeMediaItemsMock[0]
});
const expected = YoutubeMediaItemsMock[0];
expect(actual.index).toBe(expected.id);
});
Spec - select a video in now playlist
it('should select the chosen video', () => {
const state = { index: '', videos: [...YoutubeMediaItemsMock], filter: '' };
const actual = nowPlaylist(state, {
type: NowPlaylistActions.SELECT,
payload: YoutubeMediaItemsMock[0]
});
const expected = YoutubeMediaItemsMock[0];
expect(actual.index).toBe(expected.id);
});
Spec - select a video in now playlist
it('should select the chosen video', () => {
const state = { index: '', videos: [...YoutubeMediaItemsMock], filter: '' };
const actual = nowPlaylist(state, {
type: NowPlaylistActions.SELECT,
payload: YoutubeMediaItemsMock[0]
});
const expected = YoutubeMediaItemsMock[0];
expect(actual.index).toBe(expected.id);
});
Ngrx DevTools
Ngrx DevTools
More NgRx To Explore:
ngrx/router
ngrx/db
...
Thanks!
ANY QUESTIONS?
You can find me at
@orizens
oren@orizens.com
http://orizens.com/services
NG2 + Ngrx/Store Workshop:
Register at http://goo.gl/EJmm7q
CREDITS
◦ Presentation template by SlidesCarnival
◦ http://orizens.com/wp/topics/adding-redux-with-
ngrxstore-to-angular-2-part-1/
◦ http://orizens.com/wp/topics/adding-redux-with-
ngrxstore-to-angular2-part-2-testing-reducers/
◦ http://orizens.com/wp/topics/angular-2-ngrxstore-
the-ngmodel-in-between-use-case-from-angular-1/
◦ Comprehensive Introduction to NgRx/Store by
btroncone
◦ Reactive Angular With Ngrx/Store by Rob Warmald
◦ https://github.com/ngrx/store
◦

Contenu connexe

Tendances

Workshop 20: ReactJS Part II Flux Pattern & Redux
Workshop 20: ReactJS Part II Flux Pattern & ReduxWorkshop 20: ReactJS Part II Flux Pattern & Redux
Workshop 20: ReactJS Part II Flux Pattern & ReduxVisual Engineering
 
Introduction to React & Redux
Introduction to React & ReduxIntroduction to React & Redux
Introduction to React & ReduxBoris Dinkevich
 
Workshop 14: AngularJS Parte III
Workshop 14: AngularJS Parte IIIWorkshop 14: AngularJS Parte III
Workshop 14: AngularJS Parte IIIVisual Engineering
 
Redux pattens - JSHeroes 2018
Redux pattens - JSHeroes 2018Redux pattens - JSHeroes 2018
Redux pattens - JSHeroes 2018Nir Kaufman
 
Using React, Redux and Saga with Lottoland APIs
Using React, Redux and Saga with Lottoland APIsUsing React, Redux and Saga with Lottoland APIs
Using React, Redux and Saga with Lottoland APIsMihail Gaberov
 
Boosting Angular runtime performance
Boosting Angular runtime performanceBoosting Angular runtime performance
Boosting Angular runtime performanceNir Kaufman
 
Quick start with React | DreamLab Academy #2
Quick start with React | DreamLab Academy #2Quick start with React | DreamLab Academy #2
Quick start with React | DreamLab Academy #2DreamLab
 
ReactJs presentation
ReactJs presentationReactJs presentation
ReactJs presentationnishasowdri
 
Workshop 13: AngularJS Parte II
Workshop 13: AngularJS Parte IIWorkshop 13: AngularJS Parte II
Workshop 13: AngularJS Parte IIVisual Engineering
 
Switch to React.js from AngularJS developer
Switch to React.js from AngularJS developerSwitch to React.js from AngularJS developer
Switch to React.js from AngularJS developerEugene Zharkov
 
Creating a WYSIWYG Editor with React
Creating a WYSIWYG Editor with ReactCreating a WYSIWYG Editor with React
Creating a WYSIWYG Editor with Reactpeychevi
 
Modern Web Developement
Modern Web DevelopementModern Web Developement
Modern Web Developementpeychevi
 
Workshop 19: ReactJS Introduction
Workshop 19: ReactJS IntroductionWorkshop 19: ReactJS Introduction
Workshop 19: ReactJS IntroductionVisual Engineering
 
Asyc flow control with javascript generators - redux-saga
Asyc flow control with javascript generators - redux-sagaAsyc flow control with javascript generators - redux-saga
Asyc flow control with javascript generators - redux-sagaPedro Solá
 
Redux training
Redux trainingRedux training
Redux trainingdasersoft
 
Workshop 23: ReactJS, React & Redux testing
Workshop 23: ReactJS, React & Redux testingWorkshop 23: ReactJS, React & Redux testing
Workshop 23: ReactJS, React & Redux testingVisual Engineering
 

Tendances (20)

Workshop 20: ReactJS Part II Flux Pattern & Redux
Workshop 20: ReactJS Part II Flux Pattern & ReduxWorkshop 20: ReactJS Part II Flux Pattern & Redux
Workshop 20: ReactJS Part II Flux Pattern & Redux
 
Introduction to React & Redux
Introduction to React & ReduxIntroduction to React & Redux
Introduction to React & Redux
 
Workshop 14: AngularJS Parte III
Workshop 14: AngularJS Parte IIIWorkshop 14: AngularJS Parte III
Workshop 14: AngularJS Parte III
 
Redux pattens - JSHeroes 2018
Redux pattens - JSHeroes 2018Redux pattens - JSHeroes 2018
Redux pattens - JSHeroes 2018
 
Using React, Redux and Saga with Lottoland APIs
Using React, Redux and Saga with Lottoland APIsUsing React, Redux and Saga with Lottoland APIs
Using React, Redux and Saga with Lottoland APIs
 
Boosting Angular runtime performance
Boosting Angular runtime performanceBoosting Angular runtime performance
Boosting Angular runtime performance
 
React redux
React reduxReact redux
React redux
 
Quick start with React | DreamLab Academy #2
Quick start with React | DreamLab Academy #2Quick start with React | DreamLab Academy #2
Quick start with React | DreamLab Academy #2
 
ReactJs presentation
ReactJs presentationReactJs presentation
ReactJs presentation
 
Workshop 13: AngularJS Parte II
Workshop 13: AngularJS Parte IIWorkshop 13: AngularJS Parte II
Workshop 13: AngularJS Parte II
 
React & Redux
React & ReduxReact & Redux
React & Redux
 
Switch to React.js from AngularJS developer
Switch to React.js from AngularJS developerSwitch to React.js from AngularJS developer
Switch to React.js from AngularJS developer
 
Creating a WYSIWYG Editor with React
Creating a WYSIWYG Editor with ReactCreating a WYSIWYG Editor with React
Creating a WYSIWYG Editor with React
 
Modern Web Developement
Modern Web DevelopementModern Web Developement
Modern Web Developement
 
Workshop 19: ReactJS Introduction
Workshop 19: ReactJS IntroductionWorkshop 19: ReactJS Introduction
Workshop 19: ReactJS Introduction
 
Asyc flow control with javascript generators - redux-saga
Asyc flow control with javascript generators - redux-sagaAsyc flow control with javascript generators - redux-saga
Asyc flow control with javascript generators - redux-saga
 
React&redux
React&reduxReact&redux
React&redux
 
Redux training
Redux trainingRedux training
Redux training
 
React with Redux
React with ReduxReact with Redux
React with Redux
 
Workshop 23: ReactJS, React & Redux testing
Workshop 23: ReactJS, React & Redux testingWorkshop 23: ReactJS, React & Redux testing
Workshop 23: ReactJS, React & Redux testing
 

En vedette

redux and angular - up and running
redux and angular - up and runningredux and angular - up and running
redux and angular - up and runningNir Kaufman
 
Redux data flow with angular 2
Redux data flow with angular 2Redux data flow with angular 2
Redux data flow with angular 2Gil Fink
 
Redux in Angular2 for jsbe
Redux in Angular2 for jsbeRedux in Angular2 for jsbe
Redux in Angular2 for jsbeBrecht Billiet
 
Angular Promises and Advanced Routing
Angular Promises and Advanced RoutingAngular Promises and Advanced Routing
Angular Promises and Advanced RoutingAlexe Bogdan
 
Functional Reactive Angular 2
Functional Reactive Angular 2 Functional Reactive Angular 2
Functional Reactive Angular 2 Tomasz Bak
 
Progressive web apps with Angular 2
Progressive web apps with Angular 2Progressive web apps with Angular 2
Progressive web apps with Angular 2Manfred Steyer
 

En vedette (7)

redux and angular - up and running
redux and angular - up and runningredux and angular - up and running
redux and angular - up and running
 
Redux data flow with angular 2
Redux data flow with angular 2Redux data flow with angular 2
Redux data flow with angular 2
 
Redux in Angular2 for jsbe
Redux in Angular2 for jsbeRedux in Angular2 for jsbe
Redux in Angular2 for jsbe
 
Angular Promises and Advanced Routing
Angular Promises and Advanced RoutingAngular Promises and Advanced Routing
Angular Promises and Advanced Routing
 
Angular redux
Angular reduxAngular redux
Angular redux
 
Functional Reactive Angular 2
Functional Reactive Angular 2 Functional Reactive Angular 2
Functional Reactive Angular 2
 
Progressive web apps with Angular 2
Progressive web apps with Angular 2Progressive web apps with Angular 2
Progressive web apps with Angular 2
 

Similaire à Angular2 & ngrx/store: Game of States

We sport architecture_implementation
We sport architecture_implementationWe sport architecture_implementation
We sport architecture_implementationaurelianaur
 
Getting the Most Out of jQuery Widgets
Getting the Most Out of jQuery WidgetsGetting the Most Out of jQuery Widgets
Getting the Most Out of jQuery Widgetsvelveeta_512
 
Asynchronous Programming at Netflix
Asynchronous Programming at NetflixAsynchronous Programming at Netflix
Asynchronous Programming at NetflixC4Media
 
How to create a magento controller in magento extension
How to create a magento controller in magento extensionHow to create a magento controller in magento extension
How to create a magento controller in magento extensionHendy Irawan
 
A re introduction to webpack - reactfoo - mumbai
A re introduction to webpack - reactfoo - mumbaiA re introduction to webpack - reactfoo - mumbai
A re introduction to webpack - reactfoo - mumbaiPraveen Puglia
 
준비하세요 Angular js 2.0
준비하세요 Angular js 2.0준비하세요 Angular js 2.0
준비하세요 Angular js 2.0Jeado Ko
 
React 16: new features and beyond
React 16: new features and beyondReact 16: new features and beyond
React 16: new features and beyondArtjoker
 
Backbone.js — Introduction to client-side JavaScript MVC
Backbone.js — Introduction to client-side JavaScript MVCBackbone.js — Introduction to client-side JavaScript MVC
Backbone.js — Introduction to client-side JavaScript MVCpootsbook
 
Building Video Applications with YouTube APIs
Building Video Applications with YouTube APIsBuilding Video Applications with YouTube APIs
Building Video Applications with YouTube APIsJarek Wilkiewicz
 
Magento Live Australia 2016: Request Flow
Magento Live Australia 2016: Request FlowMagento Live Australia 2016: Request Flow
Magento Live Australia 2016: Request FlowVrann Tulika
 
Enhance react app with patterns - part 1: higher order component
Enhance react app with patterns - part 1: higher order componentEnhance react app with patterns - part 1: higher order component
Enhance react app with patterns - part 1: higher order componentYao Nien Chung
 
symfony on action - WebTech 207
symfony on action - WebTech 207symfony on action - WebTech 207
symfony on action - WebTech 207patter
 
Seven Peaks Speaks - Compose Screenshot Testing Made Easy
Seven Peaks Speaks - Compose Screenshot Testing Made EasySeven Peaks Speaks - Compose Screenshot Testing Made Easy
Seven Peaks Speaks - Compose Screenshot Testing Made EasySeven Peaks Speaks
 
Ditching JQuery
Ditching JQueryDitching JQuery
Ditching JQueryhowlowck
 
Dive into React Performance
Dive into React PerformanceDive into React Performance
Dive into React PerformanceChing Ting Wu
 
Modules and injector
Modules and injectorModules and injector
Modules and injectorEyal Vardi
 
How to perform debounce in react
How to perform debounce in reactHow to perform debounce in react
How to perform debounce in reactBOSC Tech Labs
 

Similaire à Angular2 & ngrx/store: Game of States (20)

How to React Native
How to React NativeHow to React Native
How to React Native
 
We sport architecture_implementation
We sport architecture_implementationWe sport architecture_implementation
We sport architecture_implementation
 
Getting the Most Out of jQuery Widgets
Getting the Most Out of jQuery WidgetsGetting the Most Out of jQuery Widgets
Getting the Most Out of jQuery Widgets
 
Asynchronous Programming at Netflix
Asynchronous Programming at NetflixAsynchronous Programming at Netflix
Asynchronous Programming at Netflix
 
Advanced redux
Advanced reduxAdvanced redux
Advanced redux
 
How to create a magento controller in magento extension
How to create a magento controller in magento extensionHow to create a magento controller in magento extension
How to create a magento controller in magento extension
 
Clean Javascript
Clean JavascriptClean Javascript
Clean Javascript
 
A re introduction to webpack - reactfoo - mumbai
A re introduction to webpack - reactfoo - mumbaiA re introduction to webpack - reactfoo - mumbai
A re introduction to webpack - reactfoo - mumbai
 
준비하세요 Angular js 2.0
준비하세요 Angular js 2.0준비하세요 Angular js 2.0
준비하세요 Angular js 2.0
 
React 16: new features and beyond
React 16: new features and beyondReact 16: new features and beyond
React 16: new features and beyond
 
Backbone.js — Introduction to client-side JavaScript MVC
Backbone.js — Introduction to client-side JavaScript MVCBackbone.js — Introduction to client-side JavaScript MVC
Backbone.js — Introduction to client-side JavaScript MVC
 
Building Video Applications with YouTube APIs
Building Video Applications with YouTube APIsBuilding Video Applications with YouTube APIs
Building Video Applications with YouTube APIs
 
Magento Live Australia 2016: Request Flow
Magento Live Australia 2016: Request FlowMagento Live Australia 2016: Request Flow
Magento Live Australia 2016: Request Flow
 
Enhance react app with patterns - part 1: higher order component
Enhance react app with patterns - part 1: higher order componentEnhance react app with patterns - part 1: higher order component
Enhance react app with patterns - part 1: higher order component
 
symfony on action - WebTech 207
symfony on action - WebTech 207symfony on action - WebTech 207
symfony on action - WebTech 207
 
Seven Peaks Speaks - Compose Screenshot Testing Made Easy
Seven Peaks Speaks - Compose Screenshot Testing Made EasySeven Peaks Speaks - Compose Screenshot Testing Made Easy
Seven Peaks Speaks - Compose Screenshot Testing Made Easy
 
Ditching JQuery
Ditching JQueryDitching JQuery
Ditching JQuery
 
Dive into React Performance
Dive into React PerformanceDive into React Performance
Dive into React Performance
 
Modules and injector
Modules and injectorModules and injector
Modules and injector
 
How to perform debounce in react
How to perform debounce in reactHow to perform debounce in react
How to perform debounce in react
 

Dernier

办理多伦多大学毕业证成绩单|购买加拿大UTSG文凭证书
办理多伦多大学毕业证成绩单|购买加拿大UTSG文凭证书办理多伦多大学毕业证成绩单|购买加拿大UTSG文凭证书
办理多伦多大学毕业证成绩单|购买加拿大UTSG文凭证书zdzoqco
 
『澳洲文凭』买詹姆士库克大学毕业证书成绩单办理澳洲JCU文凭学位证书
『澳洲文凭』买詹姆士库克大学毕业证书成绩单办理澳洲JCU文凭学位证书『澳洲文凭』买詹姆士库克大学毕业证书成绩单办理澳洲JCU文凭学位证书
『澳洲文凭』买詹姆士库克大学毕业证书成绩单办理澳洲JCU文凭学位证书rnrncn29
 
SCM Symposium PPT Format Customer loyalty is predi
SCM Symposium PPT Format Customer loyalty is prediSCM Symposium PPT Format Customer loyalty is predi
SCM Symposium PPT Format Customer loyalty is predieusebiomeyer
 
Top 10 Interactive Website Design Trends in 2024.pptx
Top 10 Interactive Website Design Trends in 2024.pptxTop 10 Interactive Website Design Trends in 2024.pptx
Top 10 Interactive Website Design Trends in 2024.pptxDyna Gilbert
 
Unidad 4 – Redes de ordenadores (en inglés).pptx
Unidad 4 – Redes de ordenadores (en inglés).pptxUnidad 4 – Redes de ordenadores (en inglés).pptx
Unidad 4 – Redes de ordenadores (en inglés).pptxmibuzondetrabajo
 
Company Snapshot Theme for Business by Slidesgo.pptx
Company Snapshot Theme for Business by Slidesgo.pptxCompany Snapshot Theme for Business by Slidesgo.pptx
Company Snapshot Theme for Business by Slidesgo.pptxMario
 
TRENDS Enabling and inhibiting dimensions.pptx
TRENDS Enabling and inhibiting dimensions.pptxTRENDS Enabling and inhibiting dimensions.pptx
TRENDS Enabling and inhibiting dimensions.pptxAndrieCagasanAkio
 
ETHICAL HACKING dddddddddddddddfnandni.pptx
ETHICAL HACKING dddddddddddddddfnandni.pptxETHICAL HACKING dddddddddddddddfnandni.pptx
ETHICAL HACKING dddddddddddddddfnandni.pptxNIMMANAGANTI RAMAKRISHNA
 
IP addressing and IPv6, presented by Paul Wilson at IETF 119
IP addressing and IPv6, presented by Paul Wilson at IETF 119IP addressing and IPv6, presented by Paul Wilson at IETF 119
IP addressing and IPv6, presented by Paul Wilson at IETF 119APNIC
 
Film cover research (1).pptxsdasdasdasdasdasa
Film cover research (1).pptxsdasdasdasdasdasaFilm cover research (1).pptxsdasdasdasdasdasa
Film cover research (1).pptxsdasdasdasdasdasa494f574xmv
 
『澳洲文凭』买拉筹伯大学毕业证书成绩单办理澳洲LTU文凭学位证书
『澳洲文凭』买拉筹伯大学毕业证书成绩单办理澳洲LTU文凭学位证书『澳洲文凭』买拉筹伯大学毕业证书成绩单办理澳洲LTU文凭学位证书
『澳洲文凭』买拉筹伯大学毕业证书成绩单办理澳洲LTU文凭学位证书rnrncn29
 

Dernier (11)

办理多伦多大学毕业证成绩单|购买加拿大UTSG文凭证书
办理多伦多大学毕业证成绩单|购买加拿大UTSG文凭证书办理多伦多大学毕业证成绩单|购买加拿大UTSG文凭证书
办理多伦多大学毕业证成绩单|购买加拿大UTSG文凭证书
 
『澳洲文凭』买詹姆士库克大学毕业证书成绩单办理澳洲JCU文凭学位证书
『澳洲文凭』买詹姆士库克大学毕业证书成绩单办理澳洲JCU文凭学位证书『澳洲文凭』买詹姆士库克大学毕业证书成绩单办理澳洲JCU文凭学位证书
『澳洲文凭』买詹姆士库克大学毕业证书成绩单办理澳洲JCU文凭学位证书
 
SCM Symposium PPT Format Customer loyalty is predi
SCM Symposium PPT Format Customer loyalty is prediSCM Symposium PPT Format Customer loyalty is predi
SCM Symposium PPT Format Customer loyalty is predi
 
Top 10 Interactive Website Design Trends in 2024.pptx
Top 10 Interactive Website Design Trends in 2024.pptxTop 10 Interactive Website Design Trends in 2024.pptx
Top 10 Interactive Website Design Trends in 2024.pptx
 
Unidad 4 – Redes de ordenadores (en inglés).pptx
Unidad 4 – Redes de ordenadores (en inglés).pptxUnidad 4 – Redes de ordenadores (en inglés).pptx
Unidad 4 – Redes de ordenadores (en inglés).pptx
 
Company Snapshot Theme for Business by Slidesgo.pptx
Company Snapshot Theme for Business by Slidesgo.pptxCompany Snapshot Theme for Business by Slidesgo.pptx
Company Snapshot Theme for Business by Slidesgo.pptx
 
TRENDS Enabling and inhibiting dimensions.pptx
TRENDS Enabling and inhibiting dimensions.pptxTRENDS Enabling and inhibiting dimensions.pptx
TRENDS Enabling and inhibiting dimensions.pptx
 
ETHICAL HACKING dddddddddddddddfnandni.pptx
ETHICAL HACKING dddddddddddddddfnandni.pptxETHICAL HACKING dddddddddddddddfnandni.pptx
ETHICAL HACKING dddddddddddddddfnandni.pptx
 
IP addressing and IPv6, presented by Paul Wilson at IETF 119
IP addressing and IPv6, presented by Paul Wilson at IETF 119IP addressing and IPv6, presented by Paul Wilson at IETF 119
IP addressing and IPv6, presented by Paul Wilson at IETF 119
 
Film cover research (1).pptxsdasdasdasdasdasa
Film cover research (1).pptxsdasdasdasdasdasaFilm cover research (1).pptxsdasdasdasdasdasa
Film cover research (1).pptxsdasdasdasdasdasa
 
『澳洲文凭』买拉筹伯大学毕业证书成绩单办理澳洲LTU文凭学位证书
『澳洲文凭』买拉筹伯大学毕业证书成绩单办理澳洲LTU文凭学位证书『澳洲文凭』买拉筹伯大学毕业证书成绩单办理澳洲LTU文凭学位证书
『澳洲文凭』买拉筹伯大学毕业证书成绩单办理澳洲LTU文凭学位证书
 

Angular2 & ngrx/store: Game of States

  • 1. NG2 & NgRx/Store: Oren Farhi @Orizens
  • 2. hi! I AM Oren Farhi Senior Javascript Engineer Freelance Javascript Consultant & Tutor You can find me at: orizens.com github.com/orizens @orizens
  • 3. There’s Gotta Be Something Better Redux for Angular 2 with NgRx/Store
  • 4. - Problems of State Management - What is NgRx/Store - Usecase App - Echoes Player NgRx/Store In Echoes Player Agenda
  • 6. The State Of The App? ◦ Where? ◦ Share
  • 7. Current State Of The App UI ⇔ Model
  • 8. Solution: ngrx/store (benefits) 1. App State is Predictable 2. Separate Logics From UI 3. Optimization in Performance 4. Easy To Test 5. Time Travel (logs) 6. Route & State 7. Promotes Stateless Components
  • 10. Example App: Echoes Player - http://echotu.be
  • 12. Store is an observable “DB” Store { Data } { Object } [ Array ] number string { Data } { Data } { Data }
  • 13. Store - json object... bootstrap(App, [ provideStore({ videos: videosReducer }) ]);
  • 14. Reducers - CRUD the Store with Pure Functions (Observable) const videos = function(state = [], action) => { switch (action.type) { case 'ADD_VIDEO': return state.concat( action.payload ); default: return state; } }
  • 15. Reducers - CRUD the Store with Pure Functions (Observable) let sum = [1,2,3] sum.reduce( (result, value) => result + value, 0 );
  • 16. Action - dispatch an update to State through Reducers addVideo(media) { this.store.dispatch({ type: ‘ADD_VIDEO’, payload: media }); }
  • 17. Subscribe And Observe - data projection, slice store’s data @Component({ selector: ‘youtube-player’ }) constructor (store) { this.player$ = store.select(store => store.player); this.player$.subscribe(player => { this.isFullscreen = player.isFullscreen }); }
  • 18. Subscribe - data projection - listen with Observable @Component({ selector: ‘youtube-player’ }) constructor (store) { this.player$ = store.select(store => store.player); this.player$.subscribe(player => { this.isFullscreen = player.isFullscreen }); }
  • 19. Subscribe And Observe - data projection, slice store’s data let initialPlayerState = { mediaId: { videoId: 'NONE' }, media: { snippet: { title: 'No Media Yet' } }, showPlayer: true, playerState: 0, isFullscreen: false }
  • 20. UI Subscribe - “async” pipe - data projection to view <section class="player"> <player-controls [player]="player$ | async" (action)="handleControlAction($event)" ></player-controls> </section> let tempObv = player$.subscribe(player => this.player = player); tempObv.unsubscribe(); // when view is destroyed
  • 21. One Way Data Flow Component Reducer Store Action
  • 22. NgRx/Store in Echoes Player Store & The Youtube Videos Component
  • 23. Store In Echoes Player export interface EchoesState { videos: EchoesVideos; player: YoutubePlayerState; nowPlaylist: YoutubeMediaPlaylist; user: UserProfile; search: PlayerSearch; }
  • 24. Youtube Videos - SMART Component <youtube-videos>
  • 25. Youtube Videos - 2 Stateless Components (DUMB) <youtube-videos> <youtube-list> <player-search>
  • 26. Youtube Videos Component (SMART) @Component({ selector: 'youtube-videos', directives: [ PlayerSearchComponent, YoutubeList], template: ` <player-search [query]="search$ | async" (change)="resetPageToken()" (search)="search($event)" ></player-search> <youtube-list [list]="videos$ | async" (play)="playSelectedVideo($event)" (queue)="queueSelectedVideo($event)" ></youtube-list>` }) export class YoutubeVideos implements OnInit {}
  • 27. Youtube Videos Component (SMART) @Component({ selector: 'youtube-videos', directives: [ PlayerSearchComponent, YoutubeList], template: ` <player-search [query]="search$ | async" (change)="resetPageToken()" (search)="search($event)" ></player-search> <youtube-list [list]="videos$ | async" (play)="playSelectedVideo($event)" (queue)="queueSelectedVideo($event)" ></youtube-list>` }) export class YoutubeVideos implements OnInit {}
  • 28. Performance Boost For Components @Component({ selector: 'youtube-list', template: ` <youtube-media *ngFor="let media of list" [media]="media" (play)="playSelectedVideo(media)" (queue)="queueSelectedVideo(media)" (add)="addVideo(media)"> </youtube-media> `, directives: [NgFor, YoutubeMedia ], changeDetection: ChangeDetectionStrategy.OnPush }) export class YoutubeList { @Input() list: Array<any>; }
  • 29. Youtube Videos Component (SMART) @Component({ selector: 'youtube-videos', directives: [ PlayerSearchComponent, YoutubeList], template: ` <player-search [query]="search$ | async" (change)="resetPageToken()" (search)="search($event)" ></player-search> <youtube-list [list]="videos$ | async" (play)="playSelectedVideo($event)" (queue)="queueSelectedVideo($event)" ></youtube-list>` }) export class YoutubeVideos implements OnInit {}
  • 30. Youtube Videos - Connecting to Store export class YoutubeVideos implements OnInit { videos$: Observable<EchoesVideos>; search$: Observable<PlayerSearch>; constructor( private youtubeSearch: YoutubeSearch, private nowPlaylistService: NowPlaylistService, private store: Store<EchoesState>, public youtubePlayer: YoutubePlayerService) { this.videos$ = store.select(state => state.videos); this.search$ = store.select(state => state.search); } }
  • 31. Youtube Videos - Connecting to Store export class YoutubeVideos implements OnInit { videos$: Observable<EchoesVideos>; search$: Observable<PlayerSearch>; constructor( private youtubeSearch: YoutubeSearch, private nowPlaylistService: NowPlaylistService, private store: Store<EchoesState>, public youtubePlayer: YoutubePlayerService) { this.videos$ = store.select(state => state.videos); this.search$ = store.select(state => state.search); } }
  • 32. Updating the Store @Component({ selector: 'youtube-videos', directives: [ PlayerSearchComponent, YoutubeList], template: ` <player-search [query]="search$ | async" (change)="resetPageToken()" (search)="search($event)" ></player-search> <youtube-list [list]="videos$ | async" (play)="playSelectedVideo($event)" (queue)="queueSelectedVideo($event)" ></youtube-list>` }) export class YoutubeVideos implements OnInit {}
  • 33. Youtube Videos Component Interaction with store services: - YoutubeSearch - YoutubePlayer - NowPlaylist
  • 34. Youtube Videos - Updating The Store export class YoutubeVideos implements OnInit { videos$: Observable<EchoesVideos>; playerSearch$: Observable<PlayerSearch>; constructor(){ ... } search (query: string) { if (query.length) { this.youtubeSearch.search(query, false); } } queueSelectedVideo (media: GoogleApiYouTubeSearchResource) { return this.nowPlaylistService.queueVideo(media.id.videoId); } }
  • 35. Youtube Videos - Updating The Store export class YoutubeVideos implements OnInit { videos$: Observable<EchoesVideos>; playerSearch$: Observable<PlayerSearch>; constructor(){ ... } search (query: string) { if (query.length) { this.youtubeSearch.search(query, false); } } queueSelectedVideo (media: GoogleApiYouTubeSearchResource) { return this.nowPlaylistService.queueVideo(media.id.videoId); } }
  • 36. Services - dispatch to Store @Injectable() export class NowPlaylistService { constructor(public store: Store<EchoesState>) { this.playlist$ = this.store.select(state => state.nowPlaylist); } queueVideo (mediaId: string) { return this.youtubeVideosInfo.api .list(mediaId).then(response => { this.store.dispatch({ type: QUEUE, //- const imported from reducer payload: response.items[0] }); return response.items[0]; }); } }
  • 37. NowPlaylist Reducer let initialState = { videos: [], index: '', filter: '' } export const nowPlaylist = (state = initialState, action) => { switch (action.type) { case NowPlaylistActions.QUEUE: return Object.assign( ); default: return state; }
  • 38. NowPlaylist Reducer let initialState = { videos: [], index: '', filter: '' } export const nowPlaylist = (state = initialState, action) => { switch (action.type) { case NowPlaylistActions.QUEUE: return Object.assign({}, state, { videos: addMedia(state.videos, action.payload) }); default: return state; }
  • 39. Services - dispatch to Store @Injectable() export class NowPlaylistService { constructor(public store: Store<EchoesState>) { this.playlist$ = this.store.select(state => state.nowPlaylist); } queueVideo (mediaId: string) { return this.youtubeVideosInfo.api .list(mediaId).then(response => { this.store.dispatch({ type: QUEUE, //- const imported from reducer payload: response.items[0] }); return response.items[0]; }); } }
  • 41. Side Effects for Queue Video @Injectable() export class NowPlaylistEffects { constructor( store$, nowPlaylistActions youtubeVideosInfo ){} @Effect() queueVideoReady$ = this.store$ .whenAction(NowPlaylistActions.QUEUE_LOAD_VIDEO) .map<GoogleApiYouTubeSearchResource>(toPayload) .switchMap(media => this.youtubeVideosInfo.fetchVideoData(media.id. videoId) .map(media => this.nowPlaylistActions.queueVideo(media)) .catch(() => Observable.of(this.nowPlaylistActions.queueFailed(media))) ); }
  • 43. Loading the tested objects import { it, inject, async, describe, expect } from '@angular/core/testing'; import { nowPlaylist, NowPlaylistActions } from './now-playlist'; import { YoutubeMediaItemsMock } from './mocks/youtube.media. items';
  • 44. Spec - select a video in now playlist it('should select the chosen video', () => { const state = { index: '', videos: [...YoutubeMediaItemsMock], filter: '' }; const actual = nowPlaylist(state, { type: NowPlaylistActions.SELECT, payload: YoutubeMediaItemsMock[0] }); const expected = YoutubeMediaItemsMock[0]; expect(actual.index).toBe(expected.id); });
  • 45. Spec - set initial state it('should select the chosen video', () => { const state = { index: '', videos: [...YoutubeMediaItemsMock], filter: '' }; const actual = nowPlaylist(state, { type: NowPlaylistActions.SELECT, payload: YoutubeMediaItemsMock[0] }); const expected = YoutubeMediaItemsMock[0]; expect(actual.index).toBe(expected.id); });
  • 46. Spec - select a video in now playlist it('should select the chosen video', () => { const state = { index: '', videos: [...YoutubeMediaItemsMock], filter: '' }; const actual = nowPlaylist(state, { type: NowPlaylistActions.SELECT, payload: YoutubeMediaItemsMock[0] }); const expected = YoutubeMediaItemsMock[0]; expect(actual.index).toBe(expected.id); });
  • 47. Spec - select a video in now playlist it('should select the chosen video', () => { const state = { index: '', videos: [...YoutubeMediaItemsMock], filter: '' }; const actual = nowPlaylist(state, { type: NowPlaylistActions.SELECT, payload: YoutubeMediaItemsMock[0] }); const expected = YoutubeMediaItemsMock[0]; expect(actual.index).toBe(expected.id); });
  • 48. Spec - select a video in now playlist it('should select the chosen video', () => { const state = { index: '', videos: [...YoutubeMediaItemsMock], filter: '' }; const actual = nowPlaylist(state, { type: NowPlaylistActions.SELECT, payload: YoutubeMediaItemsMock[0] }); const expected = YoutubeMediaItemsMock[0]; expect(actual.index).toBe(expected.id); });
  • 51. More NgRx To Explore: ngrx/router ngrx/db ...
  • 52. Thanks! ANY QUESTIONS? You can find me at @orizens oren@orizens.com http://orizens.com/services NG2 + Ngrx/Store Workshop: Register at http://goo.gl/EJmm7q
  • 53. CREDITS ◦ Presentation template by SlidesCarnival ◦ http://orizens.com/wp/topics/adding-redux-with- ngrxstore-to-angular-2-part-1/ ◦ http://orizens.com/wp/topics/adding-redux-with- ngrxstore-to-angular2-part-2-testing-reducers/ ◦ http://orizens.com/wp/topics/angular-2-ngrxstore- the-ngmodel-in-between-use-case-from-angular-1/ ◦ Comprehensive Introduction to NgRx/Store by btroncone ◦ Reactive Angular With Ngrx/Store by Rob Warmald ◦ https://github.com/ngrx/store ◦