UNPKG

redux-requests

Version:

Manages in-flight requests with a Redux reducer - avoid issuing duplicate requests without any special logic!

100 lines (89 loc) 4.21 kB
/** * Reducer function to handle pending requests. * @param {Object} state Existing state object. * @param {Object} action Incoming action: * - Ations with the meta.httpRequest property are examined. * - The meta.httpRequest.url property is added or removed * from the current state depending on if the meta.httpRequest.done * property is set. * @return {Object} The new state. */ "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); 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; }; exports.requestsReducer = requestsReducer; exports.createRequestMiddleware = createRequestMiddleware; exports.attemptRequest = attemptRequest; function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; } function requestsReducer(state, action) { if (state === undefined) state = {}; if (!action.meta || !action.meta.httpRequest || !action.meta.httpRequest.url) { return state; } if (action.meta.httpRequest.done) { // Remove this request from the state var newState = _extends({}, state); delete newState[action.meta.httpRequest.url]; return newState; } else { // Add this request to the state return _extends({}, state, _defineProperty({}, action.meta.httpRequest.url, true)); } } /** * Creates a Redux middleware function when called. * @param {Function} selectorFunc A function to select the location in the store's state tree where * the requests reducer keeps it's state. * @return {Function} A middleware function that will only dispatch the action if the * action.meta.httpRequest.done property is false, and the * meta.httpRequest.url is not already in flight. */ function createRequestMiddleware() { var selectorFunc = arguments.length <= 0 || arguments[0] === undefined ? function (state) { return state.requests; } : arguments[0]; return function (store) { return function (next) { return function (action) { // Cancel HTTP request if there is already one pending for this URL if (action.meta && action.meta.httpRequest && !action.meta.httpRequest.done) { var requests = selectorFunc(store.getState()); if (requests[action.meta.httpRequest.url]) { // There is a request for this URL in flight already! // (Ignore the action) return; } } return next(action); }; }; }; } /** * Helper function to attempt a request and handle the response. * @param {String} url The URL the request is for. * @param {Object} actions Actions to dispatch depending on the outcome of the "makeRequest" Promise. * @param {Function} makeRequest Function that returns a Promise object. This function performs the actual request. * @param {Function} dispatch Redux store dispatch function. */ function attemptRequest(url, actions, makeRequest, dispatch) { var beginAction = _extends({}, actions.begin()); beginAction.meta = beginAction.meta || {}; beginAction.meta.httpRequest = { url: url, done: false }; if (!dispatch(beginAction)) { return; // bail out here if the middleware cancelled the dispatch } makeRequest().then(function (response) { var successAction = _extends({}, actions.success(response)); successAction.meta = successAction.meta || {}; successAction.meta.httpRequest = { url: url, done: true }; dispatch(successAction); })["catch"](function (err) { var failureAction = _extends({}, actions.failure(err)); failureAction.meta = failureAction.meta || {}; failureAction.meta.httpRequest = { url: url, done: true }; dispatch(failureAction); }); }