SlideShare a Scribd company logo
1 of 41
Download to read offline
Evan Schultz
Developer @Rangleio
Some rights reserved - Creative Commons 2.0 by-sa
BUILDING ANGULAR 2
APPLICATIONS
WITH REDUX
A Typical Complex SPA
• Lots of parts.
• Everything is connected to everything else.
• Changing anything breaks something somewhere.
Best Solutions Known as of Now
• Component-based UI.
• Unidirectional data-flow.
• A “stateless” approach deeper in the stack.
Stateless Architecture
Why Stateless is Good
• A lot of us were raised on OOP. Objects are stateful.
• The effect of calling a method depends on the arguments and
the object’s state.
• Very painful to test.
• Very hard to understand.
• Aims to mimic the real world.
• But why replicate the unnecessary complexity?
Alternative: Pure Functions
• The output of a pure function depends only on inputs.
• Pure functions have no side-effects.
• Pure functions have no state.
• Much easier to understand.
• Much easier to test.
• Very easy to build up through composition.
• Widely used on the server side today.
How State Really Becomes Painful
Component Model
Model
Model
Model
Component
Component
Component
Unidirectional Data Flow with Flux
Component
Store
API, etc.
Component
Dispatcher
Action(s)Action

Creator
Can We Do Better?
Getting More Stateless with Redux
• https://github.com/rackt/redux
• Key concepts: a single store + state “reducers”.
• Can a single store be a good idea?
• What the heck is a “reducer”?
Reducer Functions
• Basic reduce():
function addOneValue (value, state) {
return state + value;
}
[1,2,3,4,5].reduce(addOneValue, 0);
• Running through the items:
1: 0 => 1
2: 1 => 3
3: 3 => 6
4: 6 => 10
5: 10 => 15
Action Reducers in Redux
• Take an action and a state, return a new state.
• Your app’s state is a reduction over the actions.
• Each reducer operates on a subset of the global state.
• Simple reducers are combined into complex ones.
An Example
export const lineupReducer = (state: ILineup[] = INITIAL_STATE,
action) => {
switch (action.type) {
case PARTY_JOINED: return [...state, action.payload];
case PARTY_LEFT: return state
.filter(n => n.partyId !== action.payload.partyId);
case PARTY_SEATED: return state
.filter(n => n.partyId !== action.payload.partyId);
default: return state;
}
};
Testing Is Easy
describe('the lineup reducer', () => {
it('should allow parties to join the lineup', () => {
const initialState = lineupReducer([]);
const expectedState = [{ partyId: 1, numberOfPeople: 2 }];
const partyJoined = {
type: PARTY_JOINED,
payload: { partyId: 1, numberOfPeople: 2 }
};
const nextState = lineupReducer(initialState, partyJoined);
expect(nextState).to.deep.equal(expectedState);
});
});
Why Is This a Good Idea?
• Reducers are pure functions – easy to understand, easy to test.
• Reducers are synchronous.
• Data logic is 100% separated from view logic.
• You can still have modularity by combining reducers.
• New opportunities for tools.
How Do We Avoid Mutating State?
• Reducers are supposed to not change the old state. But how do
we keep them honest?
• Immutable data structures store data without introducing
“state”.
• Object.freeze() - shallow.
• “Seamless Immutable”: frozen all the way down.
• But what happens when you want to modify your data?
Derived Immutables
• You can’t change immutable objects. But you need to.
• So, you derive new ones. I.e., make a new immutable that is
different in a specified way, without altering the original.
• “Immutable.JS” is the library to use.
var newData = data.setIn(
['foo', 'bar', 'baz'],
42
);
• This is a key building block for stateless architecture.
Change Detection
• Angular 2 has OnPush change detection
• Only fires when reference to an Input changes
• Do not need to do property by property checking
• If used properly, can improve the performance of your
application
Angular 2 + Redux
=
ng2-redux
ng2-redux
• Angular 2 bindings for Redux
• https://github.com/angular-redux/ng2-redux
• npm install ng2-redux
• Store as Injectable service
• Expose store as an Observable
• Compatible with existing Redux ecosystem
• https://github.com/xgrommx/awesome-redux
Angular 2 - Register the Provider
import { bootstrap } from '@angular/platform-browser-dynamic';
import { NgRedux } from 'ng2-redux';
import { RioSampleApp } from './containers/sample-app';
import { ACTION_PROVIDERS } from './actions';
bootstrap(RioSampleApp, [
NgRedux,
ACTION_PROVIDERS
]);
Angular 2 - Configure the Store
import { combineReducers } from 'redux';
import { IMenu, menuReducer } from './menu';
import { ITables, tableReducer } from './tables';
import { ILineup, lineupReducer } from './lineup';
export interface IAppState {
lineup?: ILineup[];
menu?: IMenu;
tables?: ITables;
};
export default combineReducers<IAppState>({
lineup: lineupReducer,
menu: menuReducer,
tables: tableReducer
});
Angular 2 - Configure the Store
import { NgRedux } from 'ng2-redux';
import { IAppState } from '../reducers';
import rootReducer from '../reducers';
import { middleware, enhancers } from '../store';
@Component({
selector: 'rio-sample-app',
// ...
})
export class RioSampleApp {
constructor(private ngRedux: NgRedux<IAppState>) {
ngRedux
.configureStore(rootReducer, {}, middleware, enhancers);
}
};
Angular 2 - Dumb Component
• Receives data from container or smart component
@Input() lineup: ILineup[];
• Emits events up to the parent
@Output() partyJoined: EventEmitter<any> = new EventEmitter();
• Responsible for rendering only
Angular 2 - Create a Component
@Component({
selector: 'tb-lineup',
template: TEMPLATE,
changeDetection: ChangeDetectionStrategy.OnPush,
directives: [REACTIVE_FORM_DIRECTIVES]
})
export class Lineup {
@Input() lineup: ILineup[];
@Output() partyJoined: EventEmitter<any> = new EventEmitter();
@Output() partyLeft: EventEmitter<any> = new EventEmitter();
};
Angular 2 - Create a Template
<tr *ngFor="let party of lineup">
<td>{{party.partyId}}</td>
<td>{{party.numberOfPeople}}</td>
<td>{{party.partyName}}</td>
<td>
<button type="button"
(click)="partyLeft.emit({partyId: party.partyId})">X
</button>
</td>
</tr>
Angular 2 - Container Component
• Knows about Redux
• Responsible for getting the data from the store
• Responsible for passing down data
• Responsible for dispatching actions
• Nest where appropriate
@Component({
selector: 'tb-home',
template: `<tb-lineup [lineup]="lineup$ | async"
(partyJoined)="partyJoined($event)"
(partyLeft)="partyLeft($event)">
</tb-lineup>`,
directives: [Lineup, RioContainer, Panel, Table, Menu]
})
export class HomePage {
// ...
}
Angular 2 - Container Template
export class HomePage {
constructor(private _ngRedux: NgRedux<IAppState>,
private _lineupActions: LineupActions) { }
partyJoined({numberOfPeople, partyName}) {
this._lineupActions.joinLine(numberOfPeople, partyName);
}
partyLeft({partyId}) {
this._lineupActions.leaveLine(partyId);
}
Angular 2 - Container Class
Angular 2 - ngRedux.select
export class HomePage {
constructor(private _ngRedux: NgRedux<IAppState>) { }
/* ... */
ngOnInit() {
this.lineup$ = this._ngRedux.select('lineup');
this.lineupByFunction$ = this._ngRedux
.select(state => state.lineup);
this.observable = this._ngRedux
.select(state=>state.lineup)
.map(line=>line.filter(n => n.numberOfPeople >= 4))
.combineLatest(/*....*/)
}
Angular 2 - @select
export class HomePage {
@select() lineup$: Observable<ILineup[]>;
@select('lineup') lineupByKey$: Observable<ILineup[]>;
@select(state => state.lineup)
lineupByFunction$: Observable<ILineup[]>;
}
Angular 2 - Dispatching Actions
• ngRedux.dispatch
• Works with Redux middleware
• Can dispatch from component, or ActionServices
• Final action that is sent to the reducer is a plain JSON object
Angular 2 - From a Component
@Component({ /* ... */})
export class HomePage {
constructor(private _ngRedux: NgRedux<IAppState>) { }
partyJoined({numberOfPeople, partyName}) {
this._ngRedux.dispatch<any>(joinLine(numberOfPeople, partyName));
}
};
import { joinLine } from ‘../actions';
Angular 2 - ActionServices
• Injectable services
• Can access your other Angular 2 Services
• Access to NgRedux and it’s store methods
• subscribe
• getState
• dispatch
• etc …
Angular 2 - Synchronous Actions
@Injectable()
export class LineupActions {
constructor(private _ngRedux: NgRedux<IAppState>,
private _party: PartyService) { }
leaveLine(partyId) {
this._ngRedux.dispatch({
type: PARTY_LEFT,
payload: { partyId }
});
}
}
Handling Asyncronous Actions
• Call an action creator to initiate a request.
• Action creator emits an action to inform everyone that a
request was made.
• Action creator emits an action to inform everyone that a
request was completed. (Or when it fails.)
• Push details of making a request into a module.
Angular 2 - Async Actions
@Injectable()
export class LineupActions {
constructor(private _ngRedux: NgRedux<IAppState>,
private _party: PartyService) { }
joinLine(numberOfPeople, partyName) {
this._ngRedux.dispatch({ type: PARTY_JOINING });
this._party.getNextPartyId()
.then(partyId => this._ngRedux.dispatch({
type: PARTY_JOINED,
payload: { partyId, numberOfPeople, partyName }})
).catch(err => {
this._ngRedux.dispatch({ type: PARTY_JOIN_ERR,
payload: err });
});
};
}
Demo Time
Demo
• TrendyBrunch
• https://github.com/e-schultz/ng2-camp-example
Caveats
• Its addictive.
• You won’t be happy using anything else.
• Your friends might not understand your obsession.
THANK YOU!
Evan Schultz
@e_p82
e-schultz
Developer, rangle.io

More Related Content

What's hot

React + Redux. Best practices
React + Redux.  Best practicesReact + Redux.  Best practices
React + Redux. Best practicesClickky
 
redux and angular - up and running
redux and angular - up and runningredux and angular - up and running
redux and angular - up and runningNir Kaufman
 
Introduction to React & Redux
Introduction to React & ReduxIntroduction to React & Redux
Introduction to React & ReduxBoris Dinkevich
 
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
 
Introduction to ReactJS and Redux
Introduction to ReactJS and ReduxIntroduction to ReactJS and Redux
Introduction to ReactJS and ReduxBoris Dinkevich
 
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
 
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
 
Better React state management with Redux
Better React state management with ReduxBetter React state management with Redux
Better React state management with ReduxMaurice De Beijer [MVP]
 
State Models for React with Redux
State Models for React with ReduxState Models for React with Redux
State Models for React with ReduxStephan Schmidt
 
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
 
Workshop 19: ReactJS Introduction
Workshop 19: ReactJS IntroductionWorkshop 19: ReactJS Introduction
Workshop 19: ReactJS IntroductionVisual Engineering
 
Redux training
Redux trainingRedux training
Redux trainingdasersoft
 

What's hot (20)

React + Redux. Best practices
React + Redux.  Best practicesReact + Redux.  Best practices
React + Redux. Best practices
 
redux and angular - up and running
redux and angular - up and runningredux and angular - up and running
redux and angular - up and running
 
Introduction to React & Redux
Introduction to React & ReduxIntroduction to React & Redux
Introduction to React & Redux
 
Boosting Angular runtime performance
Boosting Angular runtime performanceBoosting Angular runtime performance
Boosting Angular runtime performance
 
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
 
Introduction to ReactJS and Redux
Introduction to ReactJS and ReduxIntroduction to ReactJS and Redux
Introduction to ReactJS and Redux
 
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
 
Ngrx
NgrxNgrx
Ngrx
 
React & Redux
React & ReduxReact & Redux
React & Redux
 
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
 
Better React state management with Redux
Better React state management with ReduxBetter React state management with Redux
Better React state management with Redux
 
React redux
React reduxReact redux
React redux
 
Advanced redux
Advanced reduxAdvanced redux
Advanced redux
 
Let's Redux!
Let's Redux!Let's Redux!
Let's Redux!
 
React&redux
React&reduxReact&redux
React&redux
 
State Models for React with Redux
State Models for React with ReduxState Models for React with Redux
State Models for React with Redux
 
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
 
Workshop 19: ReactJS Introduction
Workshop 19: ReactJS IntroductionWorkshop 19: ReactJS Introduction
Workshop 19: ReactJS Introduction
 
Redux training
Redux trainingRedux training
Redux training
 

Similar to Evan Schultz - Angular Camp - ng2-redux

Паразитируем на React-экосистеме (Angular 4+) / Алексей Охрименко (IPONWEB)
Паразитируем на React-экосистеме (Angular 4+) / Алексей Охрименко (IPONWEB)Паразитируем на React-экосистеме (Angular 4+) / Алексей Охрименко (IPONWEB)
Паразитируем на React-экосистеме (Angular 4+) / Алексей Охрименко (IPONWEB)Ontico
 
Introducing Vuex in your project
Introducing Vuex in your projectIntroducing Vuex in your project
Introducing Vuex in your projectDenny Biasiolli
 
State manager in Vue.js, from zero to Vuex
State manager in Vue.js, from zero to VuexState manager in Vue.js, from zero to Vuex
State manager in Vue.js, from zero to VuexCommit University
 
[FEConf Korea 2017]Angular 컴포넌트 대화법
[FEConf Korea 2017]Angular 컴포넌트 대화법[FEConf Korea 2017]Angular 컴포넌트 대화법
[FEConf Korea 2017]Angular 컴포넌트 대화법Jeado Ko
 
Peggy angular 2 in meteor
Peggy   angular 2 in meteorPeggy   angular 2 in meteor
Peggy angular 2 in meteorLearningTech
 
Angular 2 Migration - JHipster Meetup 6
Angular 2 Migration - JHipster Meetup 6Angular 2 Migration - JHipster Meetup 6
Angular 2 Migration - JHipster Meetup 6William Marques
 
Commit University - Exploring Angular 2
Commit University - Exploring Angular 2Commit University - Exploring Angular 2
Commit University - Exploring Angular 2Commit University
 
Angular2 workshop
Angular2 workshopAngular2 workshop
Angular2 workshopNir Kaufman
 
Battle of React State Managers in frontend applications
Battle of React State Managers in frontend applicationsBattle of React State Managers in frontend applications
Battle of React State Managers in frontend applicationsEvangelia Mitsopoulou
 
Exploring Angular 2 - Episode 2
Exploring Angular 2 - Episode 2Exploring Angular 2 - Episode 2
Exploring Angular 2 - Episode 2Ahmed Moawad
 
Hidden Docs in Angular
Hidden Docs in AngularHidden Docs in Angular
Hidden Docs in AngularYadong Xie
 
React 16: new features and beyond
React 16: new features and beyondReact 16: new features and beyond
React 16: new features and beyondArtjoker
 
angular fundamentals.pdf angular fundamentals.pdf
angular fundamentals.pdf angular fundamentals.pdfangular fundamentals.pdf angular fundamentals.pdf
angular fundamentals.pdf angular fundamentals.pdfNuttavutThongjor1
 
React + Redux Introduction
React + Redux IntroductionReact + Redux Introduction
React + Redux IntroductionNikolaus Graf
 

Similar to Evan Schultz - Angular Camp - ng2-redux (20)

Паразитируем на React-экосистеме (Angular 4+) / Алексей Охрименко (IPONWEB)
Паразитируем на React-экосистеме (Angular 4+) / Алексей Охрименко (IPONWEB)Паразитируем на React-экосистеме (Angular 4+) / Алексей Охрименко (IPONWEB)
Паразитируем на React-экосистеме (Angular 4+) / Алексей Охрименко (IPONWEB)
 
Introducing Vuex in your project
Introducing Vuex in your projectIntroducing Vuex in your project
Introducing Vuex in your project
 
State manager in Vue.js, from zero to Vuex
State manager in Vue.js, from zero to VuexState manager in Vue.js, from zero to Vuex
State manager in Vue.js, from zero to Vuex
 
[FEConf Korea 2017]Angular 컴포넌트 대화법
[FEConf Korea 2017]Angular 컴포넌트 대화법[FEConf Korea 2017]Angular 컴포넌트 대화법
[FEConf Korea 2017]Angular 컴포넌트 대화법
 
Peggy angular 2 in meteor
Peggy   angular 2 in meteorPeggy   angular 2 in meteor
Peggy angular 2 in meteor
 
Angular 2 Migration - JHipster Meetup 6
Angular 2 Migration - JHipster Meetup 6Angular 2 Migration - JHipster Meetup 6
Angular 2 Migration - JHipster Meetup 6
 
Commit University - Exploring Angular 2
Commit University - Exploring Angular 2Commit University - Exploring Angular 2
Commit University - Exploring Angular 2
 
Side effects-con-redux
Side effects-con-reduxSide effects-con-redux
Side effects-con-redux
 
Introduction to Redux
Introduction to ReduxIntroduction to Redux
Introduction to Redux
 
Angular2 + rxjs
Angular2 + rxjsAngular2 + rxjs
Angular2 + rxjs
 
Angular2 workshop
Angular2 workshopAngular2 workshop
Angular2 workshop
 
Battle of React State Managers in frontend applications
Battle of React State Managers in frontend applicationsBattle of React State Managers in frontend applications
Battle of React State Managers in frontend applications
 
Exploring Angular 2 - Episode 2
Exploring Angular 2 - Episode 2Exploring Angular 2 - Episode 2
Exploring Angular 2 - Episode 2
 
React hooks
React hooksReact hooks
React hooks
 
Hidden Docs in Angular
Hidden Docs in AngularHidden Docs in Angular
Hidden Docs in Angular
 
Routing to components
Routing to componentsRouting to components
Routing to components
 
React 16: new features and beyond
React 16: new features and beyondReact 16: new features and beyond
React 16: new features and beyond
 
angular fundamentals.pdf angular fundamentals.pdf
angular fundamentals.pdf angular fundamentals.pdfangular fundamentals.pdf angular fundamentals.pdf
angular fundamentals.pdf angular fundamentals.pdf
 
Ngrx slides
Ngrx slidesNgrx slides
Ngrx slides
 
React + Redux Introduction
React + Redux IntroductionReact + Redux Introduction
React + Redux Introduction
 

Evan Schultz - Angular Camp - ng2-redux

  • 1. Evan Schultz Developer @Rangleio Some rights reserved - Creative Commons 2.0 by-sa BUILDING ANGULAR 2 APPLICATIONS WITH REDUX
  • 2. A Typical Complex SPA • Lots of parts. • Everything is connected to everything else. • Changing anything breaks something somewhere.
  • 3. Best Solutions Known as of Now • Component-based UI. • Unidirectional data-flow. • A “stateless” approach deeper in the stack.
  • 5. Why Stateless is Good • A lot of us were raised on OOP. Objects are stateful. • The effect of calling a method depends on the arguments and the object’s state. • Very painful to test. • Very hard to understand. • Aims to mimic the real world. • But why replicate the unnecessary complexity?
  • 6. Alternative: Pure Functions • The output of a pure function depends only on inputs. • Pure functions have no side-effects. • Pure functions have no state. • Much easier to understand. • Much easier to test. • Very easy to build up through composition. • Widely used on the server side today.
  • 7. How State Really Becomes Painful Component Model Model Model Model Component Component Component
  • 8. Unidirectional Data Flow with Flux Component Store API, etc. Component Dispatcher Action(s)Action
 Creator
  • 9. Can We Do Better?
  • 10. Getting More Stateless with Redux • https://github.com/rackt/redux • Key concepts: a single store + state “reducers”. • Can a single store be a good idea? • What the heck is a “reducer”?
  • 11. Reducer Functions • Basic reduce(): function addOneValue (value, state) { return state + value; } [1,2,3,4,5].reduce(addOneValue, 0); • Running through the items: 1: 0 => 1 2: 1 => 3 3: 3 => 6 4: 6 => 10 5: 10 => 15
  • 12. Action Reducers in Redux • Take an action and a state, return a new state. • Your app’s state is a reduction over the actions. • Each reducer operates on a subset of the global state. • Simple reducers are combined into complex ones.
  • 13. An Example export const lineupReducer = (state: ILineup[] = INITIAL_STATE, action) => { switch (action.type) { case PARTY_JOINED: return [...state, action.payload]; case PARTY_LEFT: return state .filter(n => n.partyId !== action.payload.partyId); case PARTY_SEATED: return state .filter(n => n.partyId !== action.payload.partyId); default: return state; } };
  • 14. Testing Is Easy describe('the lineup reducer', () => { it('should allow parties to join the lineup', () => { const initialState = lineupReducer([]); const expectedState = [{ partyId: 1, numberOfPeople: 2 }]; const partyJoined = { type: PARTY_JOINED, payload: { partyId: 1, numberOfPeople: 2 } }; const nextState = lineupReducer(initialState, partyJoined); expect(nextState).to.deep.equal(expectedState); }); });
  • 15. Why Is This a Good Idea? • Reducers are pure functions – easy to understand, easy to test. • Reducers are synchronous. • Data logic is 100% separated from view logic. • You can still have modularity by combining reducers. • New opportunities for tools.
  • 16. How Do We Avoid Mutating State? • Reducers are supposed to not change the old state. But how do we keep them honest? • Immutable data structures store data without introducing “state”. • Object.freeze() - shallow. • “Seamless Immutable”: frozen all the way down. • But what happens when you want to modify your data?
  • 17. Derived Immutables • You can’t change immutable objects. But you need to. • So, you derive new ones. I.e., make a new immutable that is different in a specified way, without altering the original. • “Immutable.JS” is the library to use. var newData = data.setIn( ['foo', 'bar', 'baz'], 42 ); • This is a key building block for stateless architecture.
  • 18. Change Detection • Angular 2 has OnPush change detection • Only fires when reference to an Input changes • Do not need to do property by property checking • If used properly, can improve the performance of your application
  • 19. Angular 2 + Redux = ng2-redux
  • 20. ng2-redux • Angular 2 bindings for Redux • https://github.com/angular-redux/ng2-redux • npm install ng2-redux • Store as Injectable service • Expose store as an Observable • Compatible with existing Redux ecosystem • https://github.com/xgrommx/awesome-redux
  • 21. Angular 2 - Register the Provider import { bootstrap } from '@angular/platform-browser-dynamic'; import { NgRedux } from 'ng2-redux'; import { RioSampleApp } from './containers/sample-app'; import { ACTION_PROVIDERS } from './actions'; bootstrap(RioSampleApp, [ NgRedux, ACTION_PROVIDERS ]);
  • 22. Angular 2 - Configure the Store import { combineReducers } from 'redux'; import { IMenu, menuReducer } from './menu'; import { ITables, tableReducer } from './tables'; import { ILineup, lineupReducer } from './lineup'; export interface IAppState { lineup?: ILineup[]; menu?: IMenu; tables?: ITables; }; export default combineReducers<IAppState>({ lineup: lineupReducer, menu: menuReducer, tables: tableReducer });
  • 23. Angular 2 - Configure the Store import { NgRedux } from 'ng2-redux'; import { IAppState } from '../reducers'; import rootReducer from '../reducers'; import { middleware, enhancers } from '../store'; @Component({ selector: 'rio-sample-app', // ... }) export class RioSampleApp { constructor(private ngRedux: NgRedux<IAppState>) { ngRedux .configureStore(rootReducer, {}, middleware, enhancers); } };
  • 24. Angular 2 - Dumb Component • Receives data from container or smart component @Input() lineup: ILineup[]; • Emits events up to the parent @Output() partyJoined: EventEmitter<any> = new EventEmitter(); • Responsible for rendering only
  • 25. Angular 2 - Create a Component @Component({ selector: 'tb-lineup', template: TEMPLATE, changeDetection: ChangeDetectionStrategy.OnPush, directives: [REACTIVE_FORM_DIRECTIVES] }) export class Lineup { @Input() lineup: ILineup[]; @Output() partyJoined: EventEmitter<any> = new EventEmitter(); @Output() partyLeft: EventEmitter<any> = new EventEmitter(); };
  • 26. Angular 2 - Create a Template <tr *ngFor="let party of lineup"> <td>{{party.partyId}}</td> <td>{{party.numberOfPeople}}</td> <td>{{party.partyName}}</td> <td> <button type="button" (click)="partyLeft.emit({partyId: party.partyId})">X </button> </td> </tr>
  • 27. Angular 2 - Container Component • Knows about Redux • Responsible for getting the data from the store • Responsible for passing down data • Responsible for dispatching actions • Nest where appropriate
  • 28. @Component({ selector: 'tb-home', template: `<tb-lineup [lineup]="lineup$ | async" (partyJoined)="partyJoined($event)" (partyLeft)="partyLeft($event)"> </tb-lineup>`, directives: [Lineup, RioContainer, Panel, Table, Menu] }) export class HomePage { // ... } Angular 2 - Container Template
  • 29. export class HomePage { constructor(private _ngRedux: NgRedux<IAppState>, private _lineupActions: LineupActions) { } partyJoined({numberOfPeople, partyName}) { this._lineupActions.joinLine(numberOfPeople, partyName); } partyLeft({partyId}) { this._lineupActions.leaveLine(partyId); } Angular 2 - Container Class
  • 30. Angular 2 - ngRedux.select export class HomePage { constructor(private _ngRedux: NgRedux<IAppState>) { } /* ... */ ngOnInit() { this.lineup$ = this._ngRedux.select('lineup'); this.lineupByFunction$ = this._ngRedux .select(state => state.lineup); this.observable = this._ngRedux .select(state=>state.lineup) .map(line=>line.filter(n => n.numberOfPeople >= 4)) .combineLatest(/*....*/) }
  • 31. Angular 2 - @select export class HomePage { @select() lineup$: Observable<ILineup[]>; @select('lineup') lineupByKey$: Observable<ILineup[]>; @select(state => state.lineup) lineupByFunction$: Observable<ILineup[]>; }
  • 32. Angular 2 - Dispatching Actions • ngRedux.dispatch • Works with Redux middleware • Can dispatch from component, or ActionServices • Final action that is sent to the reducer is a plain JSON object
  • 33. Angular 2 - From a Component @Component({ /* ... */}) export class HomePage { constructor(private _ngRedux: NgRedux<IAppState>) { } partyJoined({numberOfPeople, partyName}) { this._ngRedux.dispatch<any>(joinLine(numberOfPeople, partyName)); } }; import { joinLine } from ‘../actions';
  • 34. Angular 2 - ActionServices • Injectable services • Can access your other Angular 2 Services • Access to NgRedux and it’s store methods • subscribe • getState • dispatch • etc …
  • 35. Angular 2 - Synchronous Actions @Injectable() export class LineupActions { constructor(private _ngRedux: NgRedux<IAppState>, private _party: PartyService) { } leaveLine(partyId) { this._ngRedux.dispatch({ type: PARTY_LEFT, payload: { partyId } }); } }
  • 36. Handling Asyncronous Actions • Call an action creator to initiate a request. • Action creator emits an action to inform everyone that a request was made. • Action creator emits an action to inform everyone that a request was completed. (Or when it fails.) • Push details of making a request into a module.
  • 37. Angular 2 - Async Actions @Injectable() export class LineupActions { constructor(private _ngRedux: NgRedux<IAppState>, private _party: PartyService) { } joinLine(numberOfPeople, partyName) { this._ngRedux.dispatch({ type: PARTY_JOINING }); this._party.getNextPartyId() .then(partyId => this._ngRedux.dispatch({ type: PARTY_JOINED, payload: { partyId, numberOfPeople, partyName }}) ).catch(err => { this._ngRedux.dispatch({ type: PARTY_JOIN_ERR, payload: err }); }); }; }
  • 40. Caveats • Its addictive. • You won’t be happy using anything else. • Your friends might not understand your obsession.