Skip to content

Latest commit

 

History

History
136 lines (118 loc) · 3.77 KB

File metadata and controls

136 lines (118 loc) · 3.77 KB

Thunks, Sagas, and Epics, oh my!

Redux

  1. Flow is synchronous
  2. UIs require asychronous actions or "side effects" sometimes

Redux Basics - Actions and Action Creators

Actions

  1. Simple JS Objects
  2. Requires a 'type' property
  3. Example:
{
   type: ‘ADD’,
   payload: data
}
  1. We use Redux to 'dispatch' actions to reducers to change state

Action Creators

  1. Functions that create actions
  2. Simple Example:
function addText(text) {
   return {
      type: 'ADD_TEXT',
      text
   };
}
  1. Redux Example - Encourages pure functions
dispatch(addText(text));
  1. Flux Example - NOT a pure function:
function dispatchAddTextAction(text) {
  const action = {
    type: 'ADD_TEXT',
    text
  };
  dispatch(action);
}
  1. Bound action creators
const boundAddText = text => dispatch(addText(text));
boundAddText('having fun');

Actions and Action Creators Recap

  1. Synchronous flow of actions - important!
  2. Encourage 'pure' functions (action creators) and good functional programming (composition)

Thunks, Sagas, Epics - Redux Middleware

  1. Allows asynchronous actions in Redux
  2. Thunks - returns functions
  3. Sagas - returns function generators
  4. Epics - returns functions that return observables

Thunks

  1. Create an action creator that returns a function(dispatch,getState)
  2. Chain dispatches and promises, such as calls to the server
  3. Maintain synchronous flow through your Redux app
  4. Example:
function makeSandwichesForEverybody() {
  return function (dispatch, getState) {
    // We can dispatch both plain object actions and other thunks,
    // which lets us compose the asynchronous actions in a single flow.
    return Promise.all([
        dispatch(makeASandwichWithSecretSauce('Me')),
        dispatch(makeASandwichWithSecretSauce('Friend'))
    ]).then(() =>
      dispatch(makeASandwichWithSecretSauce('Our neighbors'))
    ).then(() =>
      dispatch(getState().myMoney > 42 ?
        withdrawMoney(42) :
        apologize('Me', 'The Sandwich Shop')
      )
    );
  };
}

Sagas

  1. Create an action creator that returns a function generator
  2. Generator Example:
function* counter() {
  const index = 0;
  while (index < 3)
    yield index++;
}

const gen = counter();

console.log(gen.next().value); // 0
console.log(gen.next().value); // 1
console.log(gen.next().value); // 2
console.log(gen.next().value); // undefined
  1. Like thunks, we can handle complicated asynchronous sequences, but in "generator" style
  2. Sagas allow a cleaner way, than Thunks, to handle side effects and errors, and return the original state

Epics

  1. Create an action creator that returns an observable of actions
  2. Observable Example:
const startTicking = (actions, store) => 
  Observable.interval(1000)
    .map((i) => ({ type: 'TICK', i }))
    .takeUntil(actions.ofType('STOP_TICK'));
dispatch(startTicking);

// to stop the ticking actions at a later point
dispatch({ type: 'STOP_TICK' });
  1. Like thunks and sagas, we can handle complicated asynchronous sequences, but in "observable" style
  2. Epics, like Sagas, allow a cleaner way to handle side effects and errors, and return the original state

References