UNPKG

redux-thunk-error-handler

Version:

An error handler for thunks that, when used in conjunction with `redux-thunk-recursion-detect` can handle errors thrown in both async and sync thunks gracefully.

83 lines (63 loc) 1.91 kB
'use strict'; Object.defineProperty(exports, '__esModule', { value: true }); var reduxThunkRecursionDetect = require('redux-thunk-recursion-detect'); const handleErrorsSymbol = Symbol('handleErrors'); function createThunkErrorCatchMiddleware({ onError = logError }) { return ({ dispatch }) => { return next => action => { let act = action; if (shouldHandleError(action)) { act = wrapErrorHandling(action); } return next(act); }; function wrapErrorHandling(fn) { return (...args) => { let result; try { result = fn(...args); } catch (err) { // sync error in reducer within a thunk errorHandler(err); } if (result instanceof Promise) { // async error in thunk return result.then(value => value, e => errorHandler(e)); } return result; }; } function errorHandler(err) { const result = onError(err); if (typeof result === 'function') { // no recursive error handler calls; result[handleErrorsSymbol] = false; return dispatch(result); } return result; } }; } function shouldHandleError(action) { if (typeof action !== 'function') { return false; } if (typeof action[handleErrorsSymbol] === 'boolean') { return action[handleErrorsSymbol]; } return action[reduxThunkRecursionDetect.isNestedThunkSymbol] !== true; } /* This is useful for errors that happen in a nested thunk that is not awaited by the caller */ function forceHandleError(thunkFn) { thunkFn[handleErrorsSymbol] = true; return thunkFn; } const logError = err => console.error('Unhandled error', err); // eslint-disable-line no-console exports.default = createThunkErrorCatchMiddleware; exports.forceHandleError = forceHandleError; exports.handleErrorsSymbol = handleErrorsSymbol;