npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

redux-saga-loop-utils

v0.0.70

Published

A library that provides a better pattern to manage(start, stop, restart) loops in your redux-saga application, for example: <br>

Downloads

664

Readme

redux-saga-loop-utils

A library that provides a better pattern to manage(start, stop, restart) loops in your redux-saga application, for example:

  • HTTP request that occurs at every x inverval
  • HTTP request that retries itself upon failure at every x interval

Available APIs:

Installation

npm i redux-saga-loop-utils

Usage

Import,

import {
    repeatable,
    stoppable,
    restartable,
    retry,
    withPreviousAction,
    withPreviousResponse
} from 'redux-saga-loop-utils'

Decorate and compose your saga functions,

Use case 1: Make an HTTP request every minute

function* callAPI() {
    const {data} = yield axios.get(API_URL);
    yield put(someAction(data));
    return data;
}

function* saga() {
    yield call(
        repeatable(callAPI, {
            interval: 60000
        })
    );
}

Use case 2: Make an HTTP request every minute, and stop the loop on STOP_ACTION

function* saga() {
    yield call(
        stoppable(
            repeatable(callAPI, {
                interval: 60000
            }),
            {
                stopAction: 'STOP_ACTION'
            }
        )
    );
}

Use case 3: Make an HTTP request every minute, and restart the loop on RESTART_ACTION

function* saga() {
    yield call(
        restartable(
            repeatable(callAPI, {
                interval: 60000
            }),
            {
                restartAction: 'RESTART_ACTION'
            }
        )
    );
}

Use case 4: Compose stoppable and restartable together

function* saga() {
    yield call(
        stoppable(
            restartable(
                repeatable(callAPI, {
                    interval: 60000
                }),
                {
                    restartAction: 'RESTART_ACTION'
                }
            ),
            {
                stopAction: 'STOP_ACTION'
            }
        )
    );
}

Use case 5: Handle HTTP request error

const handleApiError = saga =>
    function*() {
        try {
            const response = yield call(saga);
            return response;
        } catch (err) {
            const {response: {status} = {}, config} = err;
            if (status === 401) {
                // Unauthenticated
            }
            if (!status) {
                // Network error
            }
            throw err;
        }
    };

function* saga() {
    yield call(
        stoppable(
            repeatable(handleApiError(callAPI), {
                interval: 60000
            }),
            {stopAction: 'STOP_ACTION'}
        )
    );
}

Use case 6: Make an HTTP request and retry upon failure

function* callAPI() {
    const {data} = axios.get(API_URL);
    return data;
}

function* saga() {
    const result = yield call(
        retry(
            callAPI,
            {
                interval: 3000
            }
        )
    );
}

Use case 7: Passing args

function* saga() {
    yield call(
        stoppable(
            restartable(
                repeatable(
                    function*(a, b, c) {
                        // a === 'a'
                        // b === 'b'
                        // c === 'c'
                    },
                    {
                        interval: 3000
                    },
                    'a'
                ),
                {
                    restartAction: 'RESTART_ACTION'
                },
                'b'
            ),
            {
                stopAction: 'STOP_ACTION'
            },
            'c'
        )
    );
}

API Reference

  • repeatable(saga, config, …args)

    config

    {
        interval: number | (() => number)
        maxRepeats?: number
    }
    • interval is a number in milliseconds or a saga function that returns a number in milliseconds
  • stoppable(saga, config, …args)

    config

    {
        startAction: string | string[]
        stopAction: string | string[]
        noAutoStart?: boolean
    }
    • By default, it commences execution without waiting for startAction, unless noAutoStart: true is specified
    • Stopped saga can always start again using startAction
  • restartable(saga, config, …args)

    config

    {
        restartAction: string | string[]
        noAutoStart?: boolean
    }
    • By default, it commences execution without waiting for restartAction, unless noAutoStart: true is specified
    • Saga can always restart again using restartAction
    • restartable is almost identical to takeLatest, the difference is with restartable you can compose your saga functions like so,
    function* saga() {
        yield call(
            restartable(
                stoppable(
                    restartable(
                        function*() {
                            // do something
                        },
                        {
                            restartAction: 'RESTART_ACTION_2'
                        }
                    ),
                    {
                        stopAction: 'STOP_ACTION'
                    }
                ),
                {
                    restartAction: 'RESTART_ACTION_1'
                }
            )
        );
    }
  • retry(saga, config, …args)

    config

    {
        interval: number
        maxRetries?: number
    }
    • interval is a number in milliseconds
    • retry will catch error thrown from within your saga, and retry accordingly
    • If maxRetries is specified, retry will throw a Max retries reached error after all retries are unsuccessful, therefore you need to handle the error on your side
    • If retry is successful, it will return the result returned from the callee saga
  • withPreviousAction(saga, config, …args)

    config

    {
        initialAction?: any
    }
    • withPreviousAction caches the last dispatched action and passes it to the callee saga like so,
    function* saga() {
        yield takeLatest(
            'SOME_ACTION',
            withPreviousAction(function*(action, previousAction) {
                // do something
            })
        );
    }
    • initialAction is undefined if not provided
  • withPreviousResponse(saga, config, …args)

    config

    {
        initialResponse?: any
    }
    • withPreviousResponse caches the last response returned from the callee saga and passes it to the caller saga like so,
    function* saga() {
        yield call(function*() {
            const {prev, next} = yield call(withPreviousResponse(callAPI));
        });
    }
    • initialResponse is undefined if not provided