JSPM

  • Created
  • Published
  • Downloads 1048967
  • Score
    100M100P100Q183536F
  • License MIT

Saga middleware for Redux to handle Side Effects

Package Exports

  • redux-saga/lib

This package does not declare an exports field, so the exports above have been automatically detected and optimized by JSPM instead. If any package subpath is missing, it is recommended to post an issue to the original package (redux-saga) to support the "exports" field. If that is not possible, create a JSPM override to customize the exports field for this package.

Readme

redux-saga

Exploration of an alternative side effect model for Redux applications.

Instead of dispatching thunks which get handled by the redux-thunk middleware. You create Sagas (not sure if the term applies correctly)

A Saga is a generator function that takes (getState, action) and can yield side effects as well as other actions.

Example

function* checkout(getState) {
  const cart = getState().cart
  try {
    // yield a side effect : an api call that returns a promise
    const cart1 = yield [api.buyProducts, cart]

    // yield an action with the response from the api call
    yield actions.checkoutSuccess(cart1)
  } catch(error) {
    // catch errors from a rejected promise
    yield actions.checkoutFailure(error)
  }
}

function* getAllProducts() {
  // you can also yield thunks
  const products = yield () => api.getProducts()
  yield actions.receiveProducts(products)
}

export default function* rootSaga(getState, action) {
  switch (action.type) {
    case types.GET_ALL_PRODUCTS:
      yield* getAllProducts(getState)
      break

    case types.CHECKOUT_REQUEST:
      yield* checkout(getState)
  }
}

plug redux-saga in the middleware pipeline

const createStoreWithSaga = applyMiddleware(
  // ...,
  sagaMiddleware(rootSaga)
)(createStore)

export default function configureStore(initialState) {
  return createStoreWithSaga(reducer, initialState)
}

The difference from redux-thunk, is that the decision of what to dispatch is not scattered throughout the action creators, but instead centralized in one place that is an integrated part of you domain logic.

How does it work

  • No application logic inside action creators. All action creators are pure factories of raw-data actions

  • All the actions hit the reducers; even "asynchronous" ones. All actions hit also the Saga.

  • Reducers are responsible of transitioning state between actions

  • Sagas are responsible of orchestrating operations (side effects or actions)

  • Sagas are generator functions that can yield

    • a thunk of the side effet (e.g. yield () => api.buyProducts(cart))
    • an array [fn, ...args] (e.g. yield () => [api.buyProducts, cart])
    • a dispatch item which will get dispatched and handled by a dedicated middleware (e.g. yield {[API_CALL]: { endpoint: 'getProducts', payload: [cart] }})

Sagas don't execute side effects themselves, they create the intended side effect. Then the side effect gets executed later by the appropriate service (either a middleware or a simple function). Services return Promise to denote their future results.

The saga middleware takes the service response and resumes the Saga generator with the resolved response. This way Sagas can describe complex workflows with a simple synchronous style. And since they are side-effect free, they can be tested simply by driving the generator function and testing the successive results.

You can get the response returned from services inside your Saga, and use it to yield further side effects or other actions. If the service responds with a rejected promise, an exception is thrown inside the generator and can be handled by a normal try/catch block.

Here the Saga code from the Shopping cart example. Note that Sagas compose using the yield * operator.

setup and run the examples

npm install

There are 2 examples ported from the Redux repos. You can observe the logged actions/effects into the console (logged via the redux-logger middleware).

Counter example npm run build-counter

Shopping Cart example npm run build-shop

There are also specs samples that test the Saga generators npm run test-counter

npm run test-shop