redux-error-snapshot
v1.3.1
Published
Redux thunk utility that aims to ease the process of retrying last failed action
Downloads
21
Readme
redux-error-snapshot
Redux thunk utility that aims to ease the process of retrying last failed action.
Since v1.0.1 this package follows the rules of Semantic versioning.
Description
Every time a dispatched action has an error
property, redux-error-snapshot
takes care of
saving a snapshot of the error'd state in its reducer, which is exposed to the user, and also
provides a set of utilities to try again the last failed action with the same exact arguments.
The user can also decide to hide some actions (which have the property error
) to the reducer:
for more informations about this possibility, checkout reducerCreator.
Install
yarn add redux-error-snapshot
Or, if you prefer using npm (but you shouldn't):
npm i -S redux-error-snapshot
Why
Because I found myself writing quite the same logic for handling the classic
Generic Error: press to try again
button / popup in different apps.
It requires redux-thunk to leverage its getState() and dispatch() methods, which I'm fond of.
What you get
Here's what this module provides out of the box:
Reducer
import { reducer as errorSnapshot } from 'redux-error-snapshot';
You have to import it inside your store manually. The simplest way would be adding it as argument in your combineReducers function, like showed in the example below. For reference, take a look here.
// reducers.js
import { combineReducers } from 'redux';
import { reducer as form } from 'redux-form';
import { reducer as errorSnapshot } from 'redux-error-snapshot';
import todo from './todo';
const rootReducer = combineReducers({
errorSnapshot,
todo,
});
export default rootReducer;
// store.js
import {
createStore,
applyMiddleware,
} from 'redux';
import thunk from 'redux-thunk';
import reducers from './reducers';
const initialState = {};
const store = createStore(
reducers,
initialState,
applyMiddleware(thunk),
);
export default store;
It contains the snapshot of the last catched error situation in the app, so you have:
error
: the error messageaction
: the function that failed last timeargs
: the same arguments passed to the action that failedmeta
: object which is guaranteed to be never null, but at least{}
The initialState of the reducer is defined as following:
initialState = {
meta: {},
};
How to correctly put values in this library's reducer:
const yourThunkAction = (arg1, arg2) =>
async (dispatch, getState) => {
try {
// your code here
} catch (err) {
// example meta structure
const meta = {
reason: err.message,
trace: err.stack,
};
dispatch({
type: 'YOUR_ERROR_TYPE',
action: yourThunkAction,
error: 'Oops, something went wrong while executing yourThunkAction',
args: [arg1, arg2],
meta,
});
}
}
Note that you can store what you want in meta
, and since v1.2.1 you can simply access its children without checking that meta isn't null first.
+import React, { PureComponent } from 'react';
+import { connect } from 'react-redux';
+import { retryLastAction } from 'redux-error-snapshot';
+
+class YourComponent extends PureComponent {
+
+ getReason = () => {
+ const { meta } = this.props.errorSnapshot;
- return meta && meta.reason;
+ return meta.reason;
+ }
+
+ // ...
+}
+
+const mapStateToProps = ({ errorSnapshot }) => ({
+ errorSnapshot,
+});
+
+export default connect(mapStateToProps, { retryLastAction })(YourComponent);
reducerCreator
You can also decide to hide some actions which have the property error
.
You just need to define a blacklist array with the types' RegEx patterns.
Every action whose type dispatched matches one of the patterns of the blacklist
is automagically ignored by the reducer.
Note that reducerCreator
has this name because it is a curried function which accepts an array
of strings as only parameter, and returns the same reducer described above.
Example:
// reducers.js
import { combineReducers } from 'redux';
import { reducer as form } from 'redux-form';
import { reducerCreator as errorSnapshotCreator } from 'redux-error-snapshot';
import todo from './todo';
const rootReducer = combineReducers({
/*
force redux-error-snapshot to ignore actions with types such as
'@@redux-form/SUBMIT_FAILED'
*/
errorSnapshot: errorSnapshotCreator(['@@redux-form/*']),
form,
todo,
});
export default rootReducer;
Actions
import {
resetErrorState,
retryLastAction,
} from 'redux-error-snapshot';
resetErrorState
: sets the errorSnapshot reducer toinitialState
, returning the typeRESET_ERROR_STATE
.retryLastAction
: dispatches the action saved in the errorSnapshot reducer. If you have decided to import the reducer with a name different thanerrorSnapshot
, you can pass its name as argument. E.g.:
import { reducer as MyErrorReducer } from 'redux-error-snapshot';
import { retryLastAction } from 'redux-error-snapshot';
// ...
dispatch(retryLastAction('MyErrorReducer'));
Typings
This project uses Flow as its type system. It automatically exports *.flow files, but not *.ts. If you do know how to automatically export TypeScript bindings without writing the same types twice, please let me know by opening a Pull Request.
Available Scripts
clean
: Deletes the compiled lib folder;build
: Runs the clean script, transpiles the code with babel to the lib folder and copies the flow references;build:watch
: Runs the build script in watch modelint
: Runs eslintflow
: Verifies if there are flow errors;test
: Runs the test suites with jest;test:watch
: Runs the tests in watch mode;test:cov
: Runs the tests and displays coverage (which should't get below 100%!)test:ci
: Tests lint, flow, and jest errors
You can build your own light version of setting the env.targets property in .babelrc to "node": "current"
.
The version deployed to npm requires NodeJS 6.11.3, which is the current LTS as of September 2017.