Skip to content
This repository has been archived by the owner on Dec 6, 2022. It is now read-only.

andykog/redux-async-flow

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

3 Commits
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

redux-async-flow

This redux middleware allows dispatching async actions, that may include:

  • promise
  • array of promises, that will be chained
  • functions returning promises
  • array of functions returning prommises, that will be chained
  • array of other async actions, that will be chained
  • functions returning anything, that will be chained
  • array of functions returning anything, that will be chained

It will handle errors in promises, dispatching ERROR actions. Exceptions, that occured in your reducer won't be swallowed and will be thrown.

Example

Lets say, you have some functions, returning promises for web api requests:

const apiLogin = password => new Promise((resolve, reject) => {
    setTimeout(() => {
        resolve(15921);
    }, 1000);
});

const apiPullUserProfile = userId => new Promise((resolve, reject) => {
    if (userId === 15921) {
        setTimeout(() => {
            resolve({
                avatarUrl: "https://img.example.org/15921/Gc2xcYMvRieoA8.png"
            });
        }, 1000);
    }
});

const apiPullAvatar = avatarUrl => new Promise((resolve, reject) => {
    if (avatarUrl === "https://img.example.org/15921/Gc2xcYMvRieoA8.png") {
        setTimeout(() => {
            resolve("Done");
        }, 1000);
    }
});

You can make corresponding actions creators:

const startLoggingIn = password => ({
    types:   ["LOGGING_IN_STARTED", "LOGGING_IN_SUCCESS", "LOGGING_IN_ERROR"],
    payload: apiLogin(password)
});

const startPullingProfile = userId => ({
    types:   ["PULLING_PROFILE_STARTED", "PULLING_PROFILE_SUCCESS", "PULLING_PROFILE_ERROR"],
    payload: apiLogin(userId)
});

const startPullingAvatar = avatarUrl => ({
    types:   ["PULLING_AVATAR_STARTED", "PULLING_AVATAR_SUCCESS", "PULLING_AVATAR_ERROR"],
    payload: apiLogin(avatarUrl)
});

Now you can make one action creator to rule them all:

const startEverything = password => ({
    types:   ["EVERYTHING_STARTED", "EVERYTHING_SUCCESS", "EVERYTHING_ERROR"],
    payload: [
        startLoggingIn(password),
        startPullingProfile,
        startPullingAvatar
    ]
});

That will results in creating actions in the following order:

{ type: EVERYTHING_STARTED }
{ type: LOGGING_IN_STARTED }
{ type: LOGGING_IN_SUCCESS, payload: 15921 /* userId */ }
{ type: PULLING_PROFILE_STARTED }
{ type: PULLING_PROFILE_SUCCESS, payload: "https://img.example.org/15921/Gc2xcYMvRieoA8.png" /* avatarUrl */ }
{ type: PULLING_AVATAR_STARTED }
{ type: PULLING_AVATAR_SUCCESS, payload: /* avatar */ }
{ type: EVERYTHING_SUCCESS }

You can transform data in the midle of chain, lets replace https with http:

const startEverything = password => ({
    types:   ["EVERYTHING_STARTED", "EVERYTHING_SUCCESS", "EVERYTHING_ERROR"],
    payload: [
        startLoggingIn(password),
        startPullingProfile,
        url => url.replace("https", "http"),
        startPullingAvatar
    ]
});

// Or even asynchronously:

const startEverything = password => ({
    types:   ["EVERYTHING_STARTED", "EVERYTHING_SUCCESS", "EVERYTHING_ERROR"],
    payload: [
        startLoggingIn(password),
        startPullingProfile,
        url => new Promise((resolve, reject) => {
            setTimeout(() => {
                resolve(url.replace("https", "http"));
            }, 500);
        }),
        startPullingAvatar
    ]
});

Any questions, propositions, pull requests are welcome in issues.

About

Abandoned

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published