‚̧Napping Panda Missionaries
    Have ideas to improve npm?Join in the discussion! ¬Ľ

    redux-error-snapshot

    1.3.1¬†‚Äʬ†Public¬†‚Äʬ†Published

    redux-error-snapshot

    Redux thunk utility that aims to ease the process of retrying last failed action.


    Travis npm npm Issue Stats

    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 message
    • action: the function that failed last time
    • args: the same arguments passed to the action that failed
    • meta: 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 to initialState, returning the type RESET_ERROR_STATE.
    • retryLastAction: dispatches the action saved in the errorSnapshot reducer. If you have decided to import the reducer with a name different than errorSnapshot, 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 mode
    • lint: Runs eslint
    • flow: 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.

    License

    MIT

    Install

    npm i redux-error-snapshot

    DownloadsWeekly Downloads

    2

    Version

    1.3.1

    License

    MIT

    Last publish

    Collaborators

    • avatar