REDUX A (better) way to manage app state
WHY REDUX? • There are other frameworks - Angular, Knockout, Backbone • Most - bidirectional data flow • Can introduce circular dependencies • State can become unpredictable • Change a small thing and break everything • Flux and Redux came up - unidirectional data flow
UNIDIRECTIONAL FLOW Redux - an implementation of FLUX Flux diagram:
DEFINE SOMETERMS • State • Actions and Action creators • Reducers • Store • …
BEFORE WE BEGIN • EcmaScript 6 (ES6) • Babel - to use ES6 in the browsers • NPM - yes, for frontend dependencies • Webpack or Browserify
NOW, LET’S DEFINETHOSE TERMS
STATE • All the data your app has { messages: [ {title: “Congrats!”, from: “Oleg”, to: “Peter”, videoUrl: “https:// super.video.mo”}, {…}, {…}], visibilityFilter: ‘NEW’, … ? }
ACTIONS • Describe new pieces of state • Plain objects • Should have a type { type: “UPDATE_MESSAGE”, messageUpdate: { id: “87784929384833”, title: “Congrats again!” } }
ACTION CREATORS • Helper functions, that create/return actions export function updateMessage(messageUpdate) { return { type: ‘UPDATE_MESSAGE’, messageUpdate } }
EASY SO FAR?
REDUCERS • Pure functions • Does not modify variables outside of its scope • Always return the same result given the same arguments • Action and previous state as parameters • Return the new state function messages(previousState, action) { var newState = … // Do not mutate the previous state. Create a new one. return newState }
LET’STRY IT previousState = { messages: [ ]
 } action = { type: ‘ADD_MESSAGE’, message: { title: ‘Congrats!’ } } What should be our new state? What should our Reducer look like?
ANDTHE ANSWER IS..
THE “RIGHT”ANSWER state = { messages: [ {title: ‘Congrats!’} ]
 } function messages(previousState, action) { switch (action.type) { case ‘ADD_MESSAGE’: // Do not mutate the previous state. Create a new one. return Object.assign({}, previousState, {messages: [...previousState.messages, action.message]} ) // cases for REMOVE_MESSAGE, EDIT_MESSAGE, etc.. default: return previousState } }
REDUCER COMPOSITION • We want to “combine” different reducers: // state { messages: […], visibilityFilter: ‘’, settings } function mainBigSuperReducer(state = {}, action) { return { messages: messages(state.messages, action), visibilityFilter: visibilityFilter(state.visibilityFilter, action), settings: settings(state.settings, action) } }
WHAT WE HAVE: • State • Actions • Reducers
STORE • Brings everything together: • holds state • allows to dispatch actions (the only way to change the store) • applies reducers to the actions • allows listeners to subscribe let store = createStore(mainBigSuperReducer)
NOWYOU ARE CLOSETO KNOWING REDUX
REDUX MAIN PRINCIPLES 1. State is stored in an object tree with a single store 2. State is read-only 3. Change is made via reducers 
 (triggered by dispatching an action)
STORE AND DATA FLOW Add Message store.dispatch(addMessage(params)) ACTION: type:‘ADD_MESSAGE’ message: { title: params.title } STORE: currentState mainReducer listeners 1. get new current state: currentState = mainReducer(currentState, ACTION) 2. notify listeners
WHAT ARETHE LISTENERS?
REACT COMES IN Add Message store.dispatch(addMessage(params)) ACTION: type:‘ADD_MESSAGE’ message: { title: params.title } STORE: currentState mainReducer listeners 1. get new current state: currentState = mainReducer(currentState, ACTION) 2. notify listeners React connect(…) handleChange() react-redux (once in the beginning)
FLUX DIAGRAM MAKES SENSE NOW
5 HOURS IN 1 SLIDE Add Message store.dispatch(addMessage(params)) ACTION: type:‘ADD_MESSAGE’ message: { title: params.title } STORE: currentState mainReducer listeners 1. get new current state: currentState = mainReducer(currentState, ACTION) 2. notify listeners React connect(…) handleChange() react-redux (once in the beginning)
SO MUCH LEFT… • More on React • Async actions and middlewear • Server-side rendering • DevTools and time-travel/replay
DISCUSSION

Redux tutorial - intro to Redux by GetLittleTech

  • 1.
    REDUX A (better) wayto manage app state
  • 2.
    WHY REDUX? • Thereare other frameworks - Angular, Knockout, Backbone • Most - bidirectional data flow • Can introduce circular dependencies • State can become unpredictable • Change a small thing and break everything • Flux and Redux came up - unidirectional data flow
  • 3.
    UNIDIRECTIONAL FLOW Redux -an implementation of FLUX Flux diagram:
  • 4.
    DEFINE SOMETERMS • State •Actions and Action creators • Reducers • Store • …
  • 5.
    BEFORE WE BEGIN •EcmaScript 6 (ES6) • Babel - to use ES6 in the browsers • NPM - yes, for frontend dependencies • Webpack or Browserify
  • 6.
  • 7.
    STATE • All thedata your app has { messages: [ {title: “Congrats!”, from: “Oleg”, to: “Peter”, videoUrl: “https:// super.video.mo”}, {…}, {…}], visibilityFilter: ‘NEW’, … ? }
  • 8.
    ACTIONS • Describe newpieces of state • Plain objects • Should have a type { type: “UPDATE_MESSAGE”, messageUpdate: { id: “87784929384833”, title: “Congrats again!” } }
  • 9.
    ACTION CREATORS • Helperfunctions, that create/return actions export function updateMessage(messageUpdate) { return { type: ‘UPDATE_MESSAGE’, messageUpdate } }
  • 10.
  • 11.
    REDUCERS • Pure functions •Does not modify variables outside of its scope • Always return the same result given the same arguments • Action and previous state as parameters • Return the new state function messages(previousState, action) { var newState = … // Do not mutate the previous state. Create a new one. return newState }
  • 12.
    LET’STRY IT previousState ={ messages: [ ]
 } action = { type: ‘ADD_MESSAGE’, message: { title: ‘Congrats!’ } } What should be our new state? What should our Reducer look like?
  • 13.
  • 14.
    THE “RIGHT”ANSWER state ={ messages: [ {title: ‘Congrats!’} ]
 } function messages(previousState, action) { switch (action.type) { case ‘ADD_MESSAGE’: // Do not mutate the previous state. Create a new one. return Object.assign({}, previousState, {messages: [...previousState.messages, action.message]} ) // cases for REMOVE_MESSAGE, EDIT_MESSAGE, etc.. default: return previousState } }
  • 15.
    REDUCER COMPOSITION • Wewant to “combine” different reducers: // state { messages: […], visibilityFilter: ‘’, settings } function mainBigSuperReducer(state = {}, action) { return { messages: messages(state.messages, action), visibilityFilter: visibilityFilter(state.visibilityFilter, action), settings: settings(state.settings, action) } }
  • 16.
    WHAT WE HAVE: •State • Actions • Reducers
  • 17.
    STORE • Brings everythingtogether: • holds state • allows to dispatch actions (the only way to change the store) • applies reducers to the actions • allows listeners to subscribe let store = createStore(mainBigSuperReducer)
  • 18.
  • 19.
    REDUX MAIN PRINCIPLES 1.State is stored in an object tree with a single store 2. State is read-only 3. Change is made via reducers 
 (triggered by dispatching an action)
  • 20.
    STORE AND DATAFLOW Add Message store.dispatch(addMessage(params)) ACTION: type:‘ADD_MESSAGE’ message: { title: params.title } STORE: currentState mainReducer listeners 1. get new current state: currentState = mainReducer(currentState, ACTION) 2. notify listeners
  • 21.
  • 22.
    REACT COMES IN AddMessage store.dispatch(addMessage(params)) ACTION: type:‘ADD_MESSAGE’ message: { title: params.title } STORE: currentState mainReducer listeners 1. get new current state: currentState = mainReducer(currentState, ACTION) 2. notify listeners React connect(…) handleChange() react-redux (once in the beginning)
  • 23.
  • 24.
    5 HOURS IN1 SLIDE Add Message store.dispatch(addMessage(params)) ACTION: type:‘ADD_MESSAGE’ message: { title: params.title } STORE: currentState mainReducer listeners 1. get new current state: currentState = mainReducer(currentState, ACTION) 2. notify listeners React connect(…) handleChange() react-redux (once in the beginning)
  • 25.
    SO MUCH LEFT… •More on React • Async actions and middlewear • Server-side rendering • DevTools and time-travel/replay
  • 26.