redux-promise-middleware-es3
Version:
Redux middleware for handling promises and optimistic updates with ES3 support
172 lines (141 loc) • 6.71 kB
JavaScript
;
var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol ? "symbol" : typeof obj; };
var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };
var _slicedToArray = function () { function sliceIterator(arr, i) { var _arr = []; var _n = true; var _d = false; var _e = undefined; try { for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i["return"]) _i["return"](); } finally { if (_d) throw _e; } } return _arr; } return function (arr, i) { if (Array.isArray(arr)) { return arr; } else if (Symbol.iterator in Object(arr)) { return sliceIterator(arr, i); } else { throw new TypeError("Invalid attempt to destructure non-iterable instance"); } }; }();
var _isPromise = require('./isPromise');
var _isPromise2 = _interopRequireDefault(_isPromise);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
var defaultTypes = ['PENDING', 'FULFILLED', 'REJECTED'];
/**
* @function promiseMiddleware
* @description
* @returns {function} thunk
*/
module.exports = function promiseMiddleware() {
var config = arguments.length <= 0 || arguments[0] === undefined ? {} : arguments[0];
var promiseTypeSuffixes = config.promiseTypeSuffixes || defaultTypes;
return function (ref) {
var dispatch = ref.dispatch;
return function (next) {
return function (action) {
if (action.payload) {
if (!(0, _isPromise2['default'])(action.payload) && !(0, _isPromise2['default'])(action.payload.promise)) {
return next(action);
}
} else {
return next(action);
}
// Deconstruct the properties of the original action object to constants
var type = action.type;
var payload = action.payload;
var meta = action.meta;
// Assign values for promise type suffixes
var _ref = (meta || {}).promiseTypeSuffixes || promiseTypeSuffixes;
var _ref2 = _slicedToArray(_ref, 3);
var PENDING = _ref2[0];
var FULFILLED = _ref2[1];
var REJECTED = _ref2[2];
/**
* @function getAction
* @description Utility function for creating a rejected or fulfilled
* flux standard action object.
* @param {boolean} Is the action rejected?
* @returns {object} action
*/
var getAction = function getAction(newPayload, isRejected) {
return _extends({
type: type + '_' + (isRejected ? REJECTED : FULFILLED)
}, newPayload ? {
payload: newPayload
} : {}, !!meta ? { meta: meta } : {}, isRejected ? {
error: true
} : {});
};
/**
* Assign values for promise and data variables. In the case the payload
* is an object with a `promise` and `data` property, the values of those
* properties will be used. In the case the payload is a promise, the
* value of the payload will be used and data will be null.
*/
var promise = void 0;
var data = void 0;
if (!(0, _isPromise2['default'])(action.payload) && _typeof(action.payload) === 'object') {
promise = payload.promise;
data = payload.data;
} else {
promise = payload;
data = null;
}
/**
* First, dispatch the pending action. This flux standard action object
* describes the pending state of a promise and will include any data
* (for optimistic updates) and/or meta from the original action.
*/
next(_extends({
type: type + '_' + PENDING
}, !!data ? { payload: data } : {}, !!meta ? { meta: meta } : {}));
/*
* @function handleReject
* @description Dispatch the rejected action and return
* an error object. The error object should contain the
* reason and the dispatched action.
* @params reason The reason the promise was rejected
* @returns {object}
*/
var handleReject = function handleReject() {
var reason = arguments.length <= 0 || arguments[0] === undefined ? null : arguments[0];
var rejectedAction = getAction(reason, true);
dispatch(rejectedAction);
var error = reason instanceof Error ? reason : new Error();
error.reason = reason;
error.action = rejectedAction;
throw error;
};
/*
* @function handleFulfill
* @description Dispatch the fulfilled action and
* return the success object. The success object should
* contain the value and the dispatched action.
* @param value The value the promise was resloved with
* @returns {object}
*/
var handleFulfill = function handleFulfill() {
var value = arguments.length <= 0 || arguments[0] === undefined ? null : arguments[0];
var resolvedAction = getAction(value, false);
dispatch(resolvedAction);
return { value: value, action: resolvedAction };
};
/**
* Second, dispatch a rejected or fulfilled action. This flux standard
* action object will describe the resolved state of the promise. In
* the case of a rejected promise, it will include an `error` property.
*
* In order to allow proper chaining of actions using `then`, a new
* promise is constructed and returned. This promise will resolve
* with two properties: (1) the value (if fulfilled) or reason
* (if rejected) and (2) the flux standard action.
*
* Rejected object:
* {
* reason: ...
* action: {
* error: true,
* type: 'ACTION_REJECTED',
* payload: ...
* }
* }
*
* Fulfilled object:
* {
* value: ...
* action: {
* type: 'ACTION_FULFILLED',
* payload: ...
* }
* }
*/
return promise.then(handleFulfill, handleReject);
};
};
};
};