Redux

 

"Because You're Not That Good At State Management"

Christopher Bloom, @illepic

slides.com/illepic/redux

Image via /u/dataMinery


(function($) {
  if ($(".header-desktop .dropdown.active-trail").length > 0) {
    $('body').addClass('header-desktop-subnav--is-active');
  }
})(jQuery);

Count the jQuery application states

  1. header_type: desktop/mobile
  2. active_trail: true/false
  3. subnav_active: true/false

Any time you toggle a class, set or read data-, or check for DOM you are storing application state in HTML.

Image via Justin Maller

The hardest part of developing frontend apps is state management.

Shut up and show me code

codepen.io/illepic/pen/yPXxEa

"Redux is a reliable state container. Applications behave consistently. Testing is easier."

the Kitchen Sink Framework

Just a view layer

Batteries included

React: Not a full framework

Vue: Not a full framework

React + Redux: View + Data flow

Vue + VueX: View + Data flow

Angular 4: Getting closer

Angular 1: Kitchen sink framework

Ember: All the things

(Redux is not React)

 

(Though it has some great React integration!)

Redux is (mostly) an implementation of the Flux architecture.

 

Flux is the application architecture that Facebook uses for building client-side web applications. It complements React's composable view components by utilizing a unidirectional data flow. It's more of a pattern rather than a formal framework, and you can start using Flux immediately without a lot of new code.

Growth of GitHub stars over time for Flux libraries (Redux in green)

Strict unidirectional data flow

 

All data follows the same lifecycle pattern. Apps are predictable and easier to understand.

Image via Michael Muraz

Action

Reducer

Store

View

API

User clicks button, ajax!

Response returned, an ACTION is DISPATCHED.

{ 
  type: ‘RESPONSE_SUCCESS’, 
  payload: response.data
}

STORE sees dispatched ACTION, runs REDUCER

REDUCER function updates STORE based on ACTION type

After state in STORE is updated, components registered to VIEW update UI

Actions

Actions are payloads of information that send data from your application to your store. They are the only source of information for the store.

{
  type: 'INCREMENT',
  value: 1,
}

They are simple objects with a type and a payload.

 

That's it. Every single thing your application can do will be documented in ACTIONS.

Reducers

Actions only describe that something happened, but don't describe how the app state changes in response. This is the job of a REDUCER.

The REDUCER is a pure function that takes the previous state and an action, and returns the next state.

function counter(state, action) {
  if (typeof state === 'undefined') {
    return 0
  }

  switch (action.type) {
    case 'INCREMENT':
      return state + 1
    case 'DECREMENT':
      return state - 1
    default:
      return state
  }
}

var store = Redux.createStore(counter);

(Quick aside about "reducing" in Javascript)

 

codepen.io/illepic/pen/ooGXBa/

Image via felixufpe

Reducer composition

"Won't my REDUCER switch statements get huge with a nontrivial app?"

 

Yes!

 

combineReducers() let's you disperse reducers throughout the project and combine them all together easily.

 

https://redux.js.org/docs/api/combineReducers.html

Reducer composition (cont'd)

// reducers/todos.js
export default function todos(state = [], action) {
  switch (action.type) {
    case 'ADD_TODO':
      return state.concat([action.text])
    default:
      return state
  }
}
// reducers/counter.js
export default function counter(state = 0, action) {
  switch (action.type) {
    case 'INCREMENT':
      return state + 1
    case 'DECREMENT':
      return state - 1
    default:
      return state
  }
}
// reducers/index.js
import { combineReducers } from 'redux'
import todos from './todos'
import counter from './counter'

export default combineReducers({
  todos,
  counter
})
// App.js
import { createStore } from 'redux'
import reducer from './reducers/index'

let store = createStore(reducer)
console.log(store.getState())
// {
//   counter: 0,
//   todos: []
// }

store.dispatch({
  type: 'ADD_TODO',
  text: 'Use Redux'
})
console.log(store.getState())
// {
//   counter: 0,
//   todos: [ 'Use Redux' ]
// }

Note the keys!

store

STORE just brings together ACTIONS and REDUCERS.

// ...
var store = Redux.createStore(counter);
// ...
function render() {
  valueEl.innerHTML = store.getState().toString()
}
store.subscribe(render)
// ...
document.getElementById('increment')
  .addEventListener('click', function () {
    store.dispatch({ type: 'INCREMENT' })
  });

And that's pretty much it

Image via Google

Immutable Data

Image via hpd-fotography

Pure Functions

Image via /u/focustoinfinity

Higher Order Functions

Higher Order Functions:

tHUNKS

Higher Order Functions:

REACT-REDUX "Higher ORder Components"

Errata

THANKS!

Made with Slides.com