redux-saga-async-action

0.3.1 • Public • Published

redux-saga-async-action

Generated with nod NPM version Build Status Coverage Status

Dispatching an action handled by redux-saga returns promise. It looks like redux-thunk, but with pure action creators.

store.dispatch({ 
  type: 'FOO',
  payload: { title: 'bar' },
  meta: {
    async: true
  }
}).then((detail) => {
  console.log('Yaay!', detail)
}).catch((error) => {
  console.log('Oops!', error)
})

redux-saga-async-action uses Flux Standard Action to determine action's payload, failure etc.

Install

$ npm install --save redux-saga-async-action

Basic setup

Add middleware to your redux configuration (before redux-saga middleware):

import { createStore, applyMiddleware } from 'redux'
import createSagaMiddleware from 'redux-saga'
import { middleware as asyncMiddleware } from 'redux-saga-async-action'
 
const sagaMiddleware = createSagaMiddleware()
const store = createStore({}, applyMiddleware(asyncMiddleware, sagaMiddleware))

Usage

Add meta.async to your actions and receive key on response actions:

const resourceCreateRequest = data => ({
  type: 'RESOURCE_CREATE_REQUEST', // you can name it as you want
  payload: data, // promise will return payload
  meta: {
    async: true
    ^
  }
})
 
const resourceCreateSuccess = (detail, key) => ({
                                       ^
  type: 'RESOURCE_CREATE_SUCCESS', // name really doesn't matter
  payload: detail,
  meta: {
    async: key
           ^
  }
})
 
const resourceCreateFailure = (error, key) => ({
                                      ^
  type: 'RESOURCE_CREATE_FAILURE',
  error: true, // redux-saga-async-action will use this to determine if that's a failed action
  payload: error,
  meta: {
    async: key
           ^
  }
})

redux-saga-async-action will automatically transform your request action and inject a key into it.

Handle actions with redux-saga like you normally do, but you'll need to grab key from the request action and pass it to the response actions:

// worker saga
// async will be transformed in something like 'RESOURCE_CREATE_REQUEST_1234567890123456_REQUEST'
// the 16 digits in the middle are necessary to handle multiple async actions with same type
function* createResource(data, { async }) {
                                 ^
  try {
    const detail = yield call(api.post, '/resources', data)
    yield put(resourceCreateSuccess(detail, async))
                                            ^
  } catch (e) {
    yield put(resourceCreateFailure(e, async))
                                       ^
  }
}
 
// watcher saga
function* watchResourceCreateRequest() {
  while (true) {
    const { payload, meta } = yield take('RESOURCE_CREATE_REQUEST')
                     ^
    yield call(createResource, payload, meta)
                                        ^
  }
}

Dispatch the action from somewhere. Since that's being intercepted by asyncMiddleware cause you set meta.async on the action, dispatch will return a promise.

store.dispatch(resourceCreateRequest({ title: 'foo' })).then((detail) => {
  // detail is the action payload property
  console.log('Yaay!', detail)
}).catch((error) => {
  // error is the action payload property
  console.log('Oops!', error)
})

Usage with selectors

To use isPending and hasFailed selectors, you'll need to add the asyncReducer to your store:

import { combineReducers } from 'redux'
import { reducer as asyncReducer } from 'redux-saga-async-action'
 
const reducer = combineReducers({
  async: asyncReducer,
  // your reducers...
})

Now you can use selectors on your containers:

import { isPending, hasFailed } from 'redux-saga-async-action'
 
const mapStateToProps = state => ({
  loading: isPending(state, 'RESOURCE_CREATE_REQUEST'),
  error: hasFailed(state, 'RESOURCE_CREATE_REQUEST')
})

API

isPending

Tells if an action is pending

Parameters

Examples

const mapStateToProps = state => ({
  fooIsPending: isPending(state, 'FOO'),
  fooOrBarIsPending: isPending(state, ['FOO', 'BAR']),
  anythingIsPending: isPending(state)
})

Returns boolean

hasFailed

Tells if an action has failed

Parameters

Examples

const mapStateToProps = state => ({
  fooHasFailed: hasFailed(state, 'FOO'),
  fooOrBarHasFailed: hasFailed(state, ['FOO', 'BAR']),
  anythingHasFailed: hasFailed(state)
})

Returns boolean

License

MIT © Diego Haz

Package Sidebar

Install

npm i redux-saga-async-action

Weekly Downloads

3

Version

0.3.1

License

MIT

Last publish

Collaborators

  • diegohaz