redux-saga-loop-utils v0.0.70
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,
```javascript
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** ```javascript
{ initialAction?: any }
- **withPreviousAction** caches the last dispatched action and passes it to the callee saga like so, ```javascript 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
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago