redux-saga-async-action
v0.3.1
Published
Dispatching an action handled by redux-saga returns promise
Downloads
2
Maintainers
Readme
redux-saga-async-action
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'spayload
,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