REDUX &
ANGULAR 2.0
Nir Kaufman
Nir Kaufman
Head of Angular Development @ 500Tech
- AngularJS evangelist
- International speaker
- Guitar player
*Photoshop
THE CHALLENGE
SPA BECOME
INCREASINGLY
COMPLICATED
THERE IS NOTHING
WRONG WITH THE
MVC PATTERN
IF YOU ARE
BUILDING A CRUD
APPLICATION
BUT WE ARE
PUSHING THE
ENVELOPE AS MUCH
AS WE CAN
MANAGING AN
EVER-CHANGING STATE
IS A HARD TASK
EVERYTHING IS
CONNECTED TO
EVERYTHING
VIEW
VIEW
CONTROLLER
VIEW
CONTROLLER
MODEL MODEL
VIEW
CONTROLLER
MODEL MODEL MODEL
VIEW
CONTROLLER
MODEL MODEL MODEL
MODEL
VIEW
CONTROLLER
MODEL MODEL MODEL MODEL
MODEL
VIEW
CONTROLLER
MODEL
LIBRARY
MODEL MODEL MODEL
MODEL MODEL
VIEW
CONTROLLER
MODEL
LIBRARYLIBRARY
MODEL MODEL MODEL
MODEL MODEL MODEL MODEL
CHANGING SOMETHING
BREAKS SOMETHING
SOMEWHERE
ENTER REDUX
https://github.com/nirkaufman/redux-playground
http://tinyurl.com/hq23lsa
PLAY ALONG
REDUX IS A LIBRARY
FOR IMPLEMNETING A
DESIGN PATTERN
REDUX ATTEMPTS TO
MAKE STATE MUTATIONS
PREDICTABLE
INSPIRED BY
FLUX, CQRS &
EVENT SOURCING
REDUX INTREDUCE
THREE PRINCIPLES
SINGLE SOURCE
OF TRUTH
the state of your whole application is stored in
an object tree within a single store
THE TRUTH IS OUT THERE
class SideBarComponent {



private visible: boolean;



toggle(){

this.visible = !this.visible

}

}
Stateful components
class TabsComponent {



private activeTab:Tab;



activateTab(tab) {

this.activeTab = tab;

}

}
Stateful components
class Accounts {



private accounts: Account[];



getAccounts() {

return this.accounts;

}

}
Data Models
const state = {

tabs: [],

accounts: [],

sidebar: {}

};
Application state
app state
STOREUI
stateless UI
THE STATE IS
READ ONLY
the only way to mutate the state is to emit an
action, an object describing what happened
class Store {



private state: Object;



getState(){

return this.state;

} 

}
Read-only State
STOREUI
STATEgetState()
STOREUI
STATEgetState()
ACTIONdispatch(action)
PURE FUNCTIONS
to specify how the state tree is transformed
by actions, you write pure functions.
PURE FUNCTION
return value is only determined by its input values,
without observable side effects.
PURE
FUNCTION
Current State
Action
Next State
Calculate the next state
PURE
FUNCTION
Current State
Action
Next State
Reducer
Calculate the next state
Uni directional data flow
UI STOREactions
state
ENTER THE STORE
THE STORE IS THE
HEART OF REDUX
TO CREATE A STORE
WE NEED A REDUCER
import { createStore } from 'redux';



const store = createStore(reducer);
import { createStore } from 'redux';



const store = createStore(reducer);
REDUCE METHOD
applies a function against an accumulator and
each value of the array (from left-to-right) to
reduce it to a...
function sum (previousVal, currentVal) {

return previousVal + currentVal;

}



[0, 1, 2, 3, 4].reduce(sum);
// => 10
Red...
EVENT SOURCING
capture all changes to an application state as a
sequence of events.
function counter (state, action) {

switch (action) {

case 'up':

return state + 1;

case 'down':

return state - 1;

def...
THE REDUCER RETURNS
THE NEXT STATE
BASED ON A SEQUENCE
OF ACTIONS
THE SAME SEQUENCE
OF ACTIONS
WILL PRODUCE THE
SAME STATE
PREDICTABLE
STATE CONTAINER
HANDS ON!
implementing a working store
in less then 30 lines of code.
function createStore(reducer) {

let state = null;

const listeners = [];



function getState() {

return state;

}



fu...
STORE API
dispatch(action)
subscribe(listener)
getState()
replaceReducer(reducer)
ASYNC DATA FLOW
MIDDLEWARE
extension point between dispatching an action,
and the moment it reaches the reducer.
Async flow with middlewares
UI STOREaction
state
Async flow with middlewares
UI STORE
state
MIDDLEWARE
action action
export const middleware = store => next => action => {

return next(action)

};
Middleware
- get the current state from th...
ANGULAR & REDUX
ANGULAR IS A NEW
PLATFORM FOR BUILDING
COMPLEX MODERN SPA’S
https://github.com/nirkaufman/angular2-redux-workshop.git
http://tinyurl.com/h4bqmut
GET THE CODE
git checkout master
AN ANGULAR APP IS A
TREE OF COMPONENTS
WE MAP PROPERTIES
TO THE STATE
WE DISPATCH ACTIONS
IN REACTION TO EVENTS
COMPONENT
COMPONENT
STORE
[properties](events)
actions
state
git checkout 01_project-structure
ANGULAR 2.0
ENCOURAGING AN
OOP APPROACH
TO USE DEPENDENCY
INJECTIONS WITH REDUX
WE WRAP STUFF IN
PROVIDERS
import {createStore} from “redux";
import {RootReducer} from './reducers/root';


export class Store {



private store = ...
WE COMBINE MULTIPLY
REDUCERS TO ONE
ROOT REDUCER
import {combineReducers} from 'redux';



export const RootReducer = combineReducers({

app: (state = 0) => state

});
com...
WE NEED TO REGISTER
OUR STORE PROVIDER
ON THE MODULE
@NgModule({

declarations: [AppComponent],

imports : [BrowserModule, HttpModule],

providers : [Store],

bootstrap : [App...
NOW WE CAN INJECT
IT TO OUR COMPONENT
AND GET THE STATE!
export class AppComponent {



constructor(store: Store) {

console.log(store.state);

}

}
git checkout 02_wiring
COMMON SCENARIOS
REQUIREMENTS
CRUD operations
Authentication
Notifications
Persistance
View modes
Logging
@Injectable()

export class ListActions {



private store:Store;



constructor(_store:Store) {

this.store = _store;

}
...
git checkout 03_crud
@Injectable()

export class Auth {

private http:Http;

private URL:string;



constructor(_http:Http) {

this.http = _htt...
git checkout 04_authentication
const initialState = {

loading: false

};



export function appReducer(state = initialState, action) {



switch (action...
git checkout 05_spinner
GET READY FOR
TIME TRAVEL
DEBUGGING
class Model {



private items = [];





addItem(item) {}



updateIten(item) {...}



removeItem(item) {...}



}
separa...
class ModelCrud {



static addItem(model, item) {…}



static updateIten(model, item) {…}



static removeItem(model, ite...
git checkout 06_debugger
NEXT STEPS
Angular & Redux Workshop
https://leanpub.com/redux-book
THE COMPLETE
REDUX BOOK
Angular & Redux Workshop
RESOURCES
REDUX
http://redux.js.org/
https://egghead.io/series/getting-started-with-redux
CQRS & ...
NIR KAUFMAN
nir@500tech.com
Head of Angular Development @ 500Tech
@nirkaufman
github.com/nirkaufman
meetup.com/Angular-Aft...
Redux with angular 2 - workshop 2016
Redux with angular 2 - workshop 2016
Redux with angular 2 - workshop 2016
Redux with angular 2 - workshop 2016
Redux with angular 2 - workshop 2016
Redux with angular 2 - workshop 2016
Redux with angular 2 - workshop 2016
Nächste SlideShare
Wird geladen in …5
×

Redux with angular 2 - workshop 2016

1.495 Aufrufe

Veröffentlicht am

Slides for the 2016 Redux & Angular workshop. Redux is a popular library for state management. This workshop is about understanding how to use Redux and how to integrate it wit Angular 2

Veröffentlicht in: Technologie

Redux with angular 2 - workshop 2016

  1. 1. REDUX & ANGULAR 2.0 Nir Kaufman
  2. 2. Nir Kaufman Head of Angular Development @ 500Tech - AngularJS evangelist - International speaker - Guitar player *Photoshop
  3. 3. THE CHALLENGE
  4. 4. SPA BECOME INCREASINGLY COMPLICATED
  5. 5. THERE IS NOTHING WRONG WITH THE MVC PATTERN
  6. 6. IF YOU ARE BUILDING A CRUD APPLICATION
  7. 7. BUT WE ARE PUSHING THE ENVELOPE AS MUCH AS WE CAN
  8. 8. MANAGING AN EVER-CHANGING STATE IS A HARD TASK
  9. 9. EVERYTHING IS CONNECTED TO EVERYTHING
  10. 10. VIEW
  11. 11. VIEW CONTROLLER
  12. 12. VIEW CONTROLLER MODEL MODEL
  13. 13. VIEW CONTROLLER MODEL MODEL MODEL
  14. 14. VIEW CONTROLLER MODEL MODEL MODEL MODEL
  15. 15. VIEW CONTROLLER MODEL MODEL MODEL MODEL MODEL
  16. 16. VIEW CONTROLLER MODEL LIBRARY MODEL MODEL MODEL MODEL MODEL
  17. 17. VIEW CONTROLLER MODEL LIBRARYLIBRARY MODEL MODEL MODEL MODEL MODEL MODEL MODEL
  18. 18. CHANGING SOMETHING BREAKS SOMETHING SOMEWHERE
  19. 19. ENTER REDUX
  20. 20. https://github.com/nirkaufman/redux-playground http://tinyurl.com/hq23lsa PLAY ALONG
  21. 21. REDUX IS A LIBRARY FOR IMPLEMNETING A DESIGN PATTERN
  22. 22. REDUX ATTEMPTS TO MAKE STATE MUTATIONS PREDICTABLE
  23. 23. INSPIRED BY FLUX, CQRS & EVENT SOURCING
  24. 24. REDUX INTREDUCE THREE PRINCIPLES
  25. 25. SINGLE SOURCE OF TRUTH the state of your whole application is stored in an object tree within a single store
  26. 26. THE TRUTH IS OUT THERE
  27. 27. class SideBarComponent {
 
 private visible: boolean;
 
 toggle(){
 this.visible = !this.visible
 }
 } Stateful components
  28. 28. class TabsComponent {
 
 private activeTab:Tab;
 
 activateTab(tab) {
 this.activeTab = tab;
 }
 } Stateful components
  29. 29. class Accounts {
 
 private accounts: Account[];
 
 getAccounts() {
 return this.accounts;
 }
 } Data Models
  30. 30. const state = {
 tabs: [],
 accounts: [],
 sidebar: {}
 }; Application state
  31. 31. app state STOREUI stateless UI
  32. 32. THE STATE IS READ ONLY the only way to mutate the state is to emit an action, an object describing what happened
  33. 33. class Store {
 
 private state: Object;
 
 getState(){
 return this.state;
 } 
 } Read-only State
  34. 34. STOREUI STATEgetState()
  35. 35. STOREUI STATEgetState() ACTIONdispatch(action)
  36. 36. PURE FUNCTIONS to specify how the state tree is transformed by actions, you write pure functions.
  37. 37. PURE FUNCTION return value is only determined by its input values, without observable side effects.
  38. 38. PURE FUNCTION Current State Action Next State Calculate the next state
  39. 39. PURE FUNCTION Current State Action Next State Reducer Calculate the next state
  40. 40. Uni directional data flow UI STOREactions state
  41. 41. ENTER THE STORE
  42. 42. THE STORE IS THE HEART OF REDUX
  43. 43. TO CREATE A STORE WE NEED A REDUCER
  44. 44. import { createStore } from 'redux';
 
 const store = createStore(reducer);
  45. 45. import { createStore } from 'redux';
 
 const store = createStore(reducer);
  46. 46. REDUCE METHOD applies a function against an accumulator and each value of the array (from left-to-right) to reduce it to a single value.
  47. 47. function sum (previousVal, currentVal) {
 return previousVal + currentVal;
 }
 
 [0, 1, 2, 3, 4].reduce(sum); // => 10 Reduce in action
  48. 48. EVENT SOURCING capture all changes to an application state as a sequence of events.
  49. 49. function counter (state, action) {
 switch (action) {
 case 'up':
 return state + 1;
 case 'down':
 return state - 1;
 default:
 return state;
 }
 }
 
 ['up', 'up', 'down'].reduce( counter, 0 ); Simple counter app
  50. 50. THE REDUCER RETURNS THE NEXT STATE BASED ON A SEQUENCE OF ACTIONS
  51. 51. THE SAME SEQUENCE OF ACTIONS WILL PRODUCE THE SAME STATE
  52. 52. PREDICTABLE STATE CONTAINER
  53. 53. HANDS ON! implementing a working store in less then 30 lines of code.
  54. 54. function createStore(reducer) {
 let state = null;
 const listeners = [];
 
 function getState() {
 return state;
 }
 
 function dispatch(action) {
 state = reducer(state, action);
 listeners.forEach( listener => listener() )
 }
 
 function subscribe(listener) {
 listeners.push(listener);
 return function unsubscribe() {
 let index = listeners.indexOf(listener);
 listeners.splice(index, 1)
 }
 }
 
 return { getState, dispatch, subscribe }
 }
  55. 55. STORE API dispatch(action) subscribe(listener) getState() replaceReducer(reducer)
  56. 56. ASYNC DATA FLOW
  57. 57. MIDDLEWARE extension point between dispatching an action, and the moment it reaches the reducer.
  58. 58. Async flow with middlewares UI STOREaction state
  59. 59. Async flow with middlewares UI STORE state MIDDLEWARE action action
  60. 60. export const middleware = store => next => action => {
 return next(action)
 }; Middleware - get the current state from the store - pass an action to the next middleware - access the provided action
  61. 61. ANGULAR & REDUX
  62. 62. ANGULAR IS A NEW PLATFORM FOR BUILDING COMPLEX MODERN SPA’S
  63. 63. https://github.com/nirkaufman/angular2-redux-workshop.git http://tinyurl.com/h4bqmut GET THE CODE
  64. 64. git checkout master
  65. 65. AN ANGULAR APP IS A TREE OF COMPONENTS
  66. 66. WE MAP PROPERTIES TO THE STATE
  67. 67. WE DISPATCH ACTIONS IN REACTION TO EVENTS
  68. 68. COMPONENT COMPONENT STORE [properties](events) actions state
  69. 69. git checkout 01_project-structure
  70. 70. ANGULAR 2.0 ENCOURAGING AN OOP APPROACH
  71. 71. TO USE DEPENDENCY INJECTIONS WITH REDUX WE WRAP STUFF IN PROVIDERS
  72. 72. import {createStore} from “redux"; import {RootReducer} from './reducers/root'; 
 export class Store {
 
 private store = createStore(rootReducer);
 
 get state() {
 return this.store.getState();
 }
 
 dispatch(action){
 this.store.dispatch(action)
 }
 }
  73. 73. WE COMBINE MULTIPLY REDUCERS TO ONE ROOT REDUCER
  74. 74. import {combineReducers} from 'redux';
 
 export const RootReducer = combineReducers({
 app: (state = 0) => state
 }); combineReducers in action
  75. 75. WE NEED TO REGISTER OUR STORE PROVIDER ON THE MODULE
  76. 76. @NgModule({
 declarations: [AppComponent],
 imports : [BrowserModule, HttpModule],
 providers : [Store],
 bootstrap : [AppComponent]
 })
  77. 77. NOW WE CAN INJECT IT TO OUR COMPONENT AND GET THE STATE!
  78. 78. export class AppComponent {
 
 constructor(store: Store) {
 console.log(store.state);
 }
 }
  79. 79. git checkout 02_wiring
  80. 80. COMMON SCENARIOS
  81. 81. REQUIREMENTS CRUD operations Authentication Notifications Persistance View modes Logging
  82. 82. @Injectable()
 export class ListActions {
 
 private store:Store;
 
 constructor(_store:Store) {
 this.store = _store;
 }
 
 add(item) {
 this.store.dispatch({
 type : LIST.ADD_ITEM,
 payload: item
 })
 }
 
 remove(item) {
 this.store.dispatch({
 type : LIST.REMOVE_ITEM,
 payload: item
 })
 }
 } The list actions class is an helper for dispatching actions to the store
  83. 83. git checkout 03_crud
  84. 84. @Injectable()
 export class Auth {
 private http:Http;
 private URL:string;
 
 constructor(_http:Http) {
 this.http = _http;
 this.URL = 'http://localhost:4000/api/login';
 }
 
 middleware = store => next => action => {
 
 if (action.type !== USER.LOGIN) {
 return next(action) 
 } else if (action.type === USER.LOGIN) {
 
 const successHandler = result => next({
 type : USER.LOGIN_SUCCESS,
 payload: result.json()
 });
 
 const errorHandler = error => next({
 type : USER.LOGIN_FAILED,
 payload: error.json()
 });
 
 this.http.post(this.URL, action.payload)
 .subscribe(successHandler, errorHandler);
 
 return next({type: APP.LOADING})
 }
 }
 } By wrapping the middleware in provider we can use angular services such as Http
  85. 85. git checkout 04_authentication
  86. 86. const initialState = {
 loading: false
 };
 
 export function appReducer(state = initialState, action) {
 
 switch (action.type) {
 case APP.LOADING:
 return Object.assign({}, state, {loading: true});
 
 case APP.READY:
 case USER.LOGIN_SUCCESS:
 return Object.assign({}, state, {loading: false});
 
 default:
 return state;
 }
 } ‘application level’ reducer can handle
  87. 87. git checkout 05_spinner
  88. 88. GET READY FOR TIME TRAVEL DEBUGGING
  89. 89. class Model {
 
 private items = [];
 
 
 addItem(item) {}
 
 updateIten(item) {...}
 
 removeItem(item) {...}
 
 } separation of state from mutation methods
  90. 90. class ModelCrud {
 
 static addItem(model, item) {…}
 
 static updateIten(model, item) {…}
 
 static removeItem(model, item) {…}
 
 } separation of state from mutation methods const Model = {
 items: []
 };
  91. 91. git checkout 06_debugger
  92. 92. NEXT STEPS
  93. 93. Angular & Redux Workshop https://leanpub.com/redux-book THE COMPLETE REDUX BOOK
  94. 94. Angular & Redux Workshop RESOURCES REDUX http://redux.js.org/ https://egghead.io/series/getting-started-with-redux CQRS & EVENT SOURCING https://msdn.microsoft.com/en-us/library/dn568103.aspx https://msdn.microsoft.com/en-us/library/dn589792.aspx ANGULAR 2 angular-2-change-detection-explained.html https://github.com/ngrx/store https://github.com/angular-redux/ng2-redux
  95. 95. NIR KAUFMAN nir@500tech.com Head of Angular Development @ 500Tech @nirkaufman github.com/nirkaufman meetup.com/Angular-AfterHours/ keep in touch!

×