/redux-effects-steps

Multiple steps version of redux-effects

Primary LanguageJavaScriptMIT LicenseMIT

redux-effects-steps

Another version of redux-effects handling error action properly.

Installation

npm install --save redux-effects-steps

Usage

Installing the middleware

import { createStore, applyMiddleware } from 'redux';
import stepsMiddleware from 'redux-effects-steps';
import rootReducer from './reducers';

const store = createStore(
  rootReducer,
  applyMiddleware(
    stepsMiddleware
  )
);

Defining action creators

import { createAction } from 'redux-actions';
import { steps } from 'redux-effects-steps';
import { fetchrRead } from 'redux-effects-fetchr';

const fetchUserRequest = createAction('FETCH_USER_REQUEST');
const fetchUserSuccess = createAction('FETCH_USER_SUCCESS');
const fetchUserFail = createAction('FETCH_USER_FAIL');

function fetchUser({ user }) {
  return steps(
    fetchUserRequest(),
    fetchrRead('users', { user }),
    [fetchUserSuccess, fetchUserFail]
  );
}

Using actions

const promise = store.dispatch(fetchUser({ user }));

Under the food

Example:

const promise = store.dispatch(steps(
    originAction,
    [firstSuccess, firstFailure],
    [secondSuccess, secondFailure]
  ));

is evaluated by redux-effects-steps like this:

const promise = store.dispatch(originAction)
    .then((result) => store.dispatch(firstSuccess(result)), (error) => store.dispatch(firstFailure(error)))
    .then((result) => store.dispatch(secondSuccess(result)), (error) => store.dispatch(secondFailure(error)));

Kind of Actions

Async Actions

Async action returns a Promise object when it's dispatched. If the dispatched action fails, the returned Promise will be rejected.

Sync Actions

Sync action returns an object which is not a Promise (by default, dispatched action itself.) when it's dispatched. If the action represents fail, it should be error action.

Defferences from redux-effects

Error handling

redux-effects:

import { createAction } from 'redux-actions';
import { bind } from 'redux-effects';
import { fetch } from 'redux-effects-fetch';

const success = createAction('FIND_USER_SUCCESS');
const failure = createAction('FIND_USER_FAILURE');

function findUser(condition) {
  return bind(fetch('/api/users', {method: 'POST', body: condition}), success, failure);
}

const finalPromise = store.dispatch(findUser(condition));

If fetch() action fails, the error action created by failure() is dispatched. And then, redux-effects resolves the next Promise, so the finalPromise isn't rejected.

This is the problem when the action creator is used with redux-form.

In this example, onSubmit() handler always succeed if the action fails.

reduxForm({ form: 'myForm', fields: [...] }, null, {
  onSubmit:(values, dispatch) => dispatch(findUser(values.user))
})(MyForm)

On the other hand, redux-effects-steps rejects the next Promise when error action is dispatched.

Action creator

redux-effects provides an action creator takes just one step.

import { bind } from 'redux-effects';

const action = bind(fetch(), success, failure);

redux-effects-steps provides an action creator takes multiple steps.

import { steps } from 'redux-effects-steps';

const action = steps(begin(),
  [fetch('/api/users')],
  [success, failure]
);

API

Action Creators

steps(origin, [...steps])

Arguments
  • origin (Array|Object)
    • One of the:
      • action (Object): A FSA compliant action object.
      • actions (Array): An array of actions.
  • steps (Array)
    • Each element is in a [success, failure] tuple Array.
    • success and failure are one of the:
      • action (Object): A FSA compliant action object.
      • actions (Array): An array of FSA compliant action object.
      • actionCreator (Function): An action creator.
    • If failure is not needed, you can pass just success instead of an Array.
Returns

(Object): A FSA compliant action object.