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.

78 lines (60 loc) 1.76 kB
import { isNestedThunkSymbol } from '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[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 export default createThunkErrorCatchMiddleware; export { forceHandleError, handleErrorsSymbol };