redux-easy-async
Version:
Redux Easy Async makes handling asynchronous actions, such as API requests, simple, reliable, and powerful
131 lines (115 loc) • 4.68 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.createAsyncReducer = undefined;
var _omit2 = require('lodash/omit');
var _omit3 = _interopRequireDefault(_omit2);
var _redux = require('redux');
var _asyncConstants = require('./async-constants');
var _constants = require('./lib/constants');
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
function _toConsumableArray(arr) { if (Array.isArray(arr)) { for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) { arr2[i] = arr[i]; } return arr2; } else { return Array.from(arr); } }
var asyncDefaultState = {
hasPendingRequests: false,
pendingRequests: []
};
var createSingleAsyncReducer = function createSingleAsyncReducer(type) {
var asyncConstants = (0, _asyncConstants.getOrCreateAsyncConstants)(type);
if (!asyncConstants) {
throw new Error(_constants.ERRORS.CREATE_ASYNC_REDUCER_INVALID_TYPE);
}
var START_TYPE = asyncConstants.START_TYPE,
SUCCESS_TYPE = asyncConstants.SUCCESS_TYPE,
FAIL_TYPE = asyncConstants.FAIL_TYPE;
return function () {
var state = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : asyncDefaultState;
var action = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
if ([START_TYPE, SUCCESS_TYPE, FAIL_TYPE].indexOf(action.type) > -1) {
var updatedPendingRequests = void 0;
if (action.type === START_TYPE) {
updatedPendingRequests = [].concat(_toConsumableArray(state.pendingRequests), [
// store the meta but omit `actionCreatorArgs` as they may be large or not serializable
(0, _omit3.default)(action.meta, 'actionCreatorArgs')]);
} else {
updatedPendingRequests = state.pendingRequests.filter(function (req) {
return req.asyncID !== action.meta.asyncID;
});
}
return {
pendingRequests: updatedPendingRequests,
hasPendingRequests: updatedPendingRequests.length > 0
};
}
return state;
};
};
/**
* Creates a requests reducer that automatically tracks the status of one or more async actions
* created with {@link createAsyncAction}. As you dispatch async actions this reducer will
* automatically update with number of requests, request meta for each, a boolean for whether any
* requests are currently pending for this request.
* @kind function
* @param {Array|String|Object|Function} types - one or more async actions to track. Either a
* single instance or an array of one or more of the following: a string (e.g. `"GET_POSTS"``), a
* constants object created with {@link createAsyncConstants}, or an async action created with
* {@link createAsyncAction}. Typically you will want to pass an array of actions to track all
* async actions for your application in one place.
* @return {function} Redux reducer automatically tracking the async action(s)
*
* @example
* import { createAsyncAction, createAsyncConstants } from '`redux-easy-async';
*
* // Types can async action, constants object, or string:
*
* // string constant
* const FETCH_POSTS = 'FETCH_POSTS';
*
* // async action
* export const fetchUser = createAsyncAction('FETCH_USER', (id) => {
* return {
* makeRequest: () => fetch(`https://myapi.com/api/user/${id}`),
* };
* });
*
* // async constant
* const fetchComments = createAsyncConstants('FETCH_COMMENTS');
*
* // now we can create a reducer from the action or constants we've defined
* const requestsReducer = createAsyncReducer([FETCH_POSTS, fetchUser, fetchComments]);
*
* // Now `requestsReducer` is reducer that automatically tracks each of the asynchronous action
* // types. It's state looks something like this to start:
* // {
* // {
* // FETCH_POSTS: {
* // hasPendingRequests: false,
* // pendingRequests: [],
* // },
* // {
* // FETCH_USER: {
* // hasPendingRequests: false,
* // pendingRequests: [],
* // }
* // {
* // FETCH_COMMENTS: {
* // hasPendingRequests: false,
* // pendingRequests: [],
* // }
* // }
*
*/
var createAsyncReducer = exports.createAsyncReducer = function createAsyncReducer(types) {
if (Array.isArray(types)) {
var reducers = types.reduce(function (acc, type) {
var asyncConstants = (0, _asyncConstants.getOrCreateAsyncConstants)(type);
if (asyncConstants) {
// eslint-disable-next-line no-param-reassign
acc[asyncConstants.NAME] = createSingleAsyncReducer(type);
}
return acc;
}, {});
return (0, _redux.combineReducers)(reducers);
}
return createSingleAsyncReducer(types);
};