# redux-pending-middleware

> A redux middleware which tracks your asynchronous Redux actions (effects) and informs about the progress through selector function

Latest version **0.5.0** (published 2020-05-25) · MIT license · 0 weekly downloads

> **Deprecated.** This package is deprecated.

## Install

```sh
npm install redux-pending-middleware
pnpm add redux-pending-middleware
yarn add redux-pending-middleware
bun add redux-pending-middleware
```

## Health

**Score 10/100 (F)** — status: deprecated.

Negative: deprecated.

## Facts

| | |
|---|---|
| Version | 0.5.0 |
| Published | 2020-05-25 |
| First published | 2020-04-30 |
| Weekly downloads | 0 |
| License | MIT |
| TypeScript types | bundled |
| Module format | ESM + CommonJS |
| Dependencies | 1 |
| Unpacked size | 70.8 KB |
| Known vulnerabilities | 0 |
| Install scripts | no |
| Author | Maksym Tarsis |
| Maintainers | maktarsis |
| Keywords | redux, pending, middleware, promise, side-effects, redux-promise, redux-pending, redux-middleware, redux-effects, redux-toolkit, redux-saga, redux-thunk, redux-promise-middleware |

## Links

- npm: https://www.npmjs.com/package/redux-pending-middleware
- npm.io page: https://npm.io/package/redux-pending-middleware

## Dependencies (1)

- [redux-saga](https://npm.io/package/redux-saga.md) ^1.1.3

## Alternatives

- [@sindresorhus/slugify](https://npm.io/package/@sindresorhus/slugify.md) — 3.7M weekly downloads
- [solid-js](https://npm.io/package/solid-js.md) — 2.7M weekly downloads
- [expo-glass-effect](https://npm.io/package/expo-glass-effect.md) — 2.5M weekly downloads
- [nanoassert](https://npm.io/package/nanoassert.md) — 780.8K weekly downloads
- [@ffmpeg/ffmpeg](https://npm.io/package/@ffmpeg/ffmpeg.md) — 529.5K weekly downloads

## Recent versions

- 0.5.0 (latest) — 2020-05-25
- 0.4.5 — 2020-05-06
- 0.4.4 — 2020-05-06
- 0.4.3 — 2020-05-06
- 0.4.2 — 2020-05-06
- 0.4.1 — 2020-05-05
- 0.4.0 — 2020-05-05
- 0.3.1 — 2020-05-05
- 0.3.0 — 2020-05-05
- 0.2.2 — 2020-05-05
- 0.2.1 — 2020-05-05
- 0.2.0 — 2020-05-05
- 0.1.3 — 2020-05-01
- 0.1.2 — 2020-04-30
- 0.1.1 — 2020-04-30
- … 1 more at https://npm.io/package/redux-pending-middleware/versions

## README

# Redux Pending Middleware

A redux [middleware](https://redux.js.org/advanced/middleware) which tracks your asynchronous [redux](http://redux.js.org) actions (effects) and informs about the progress through selector function.

<br/>

List of supported libraries that process redux effects:

- [redux-toolkit](https://github.com/reduxjs/redux-toolkit)
- [redux-saga](https://github.com/redux-saga/redux-saga)
- [redux-thunk](https://github.com/reduxjs/redux-thunk) / [redux-promise-middleware](https://github.com/pburtchaell/redux-promise-middleware)

It's worth mention that `redux-pending-middleware` allows you to code simultaneously with all the above libraries simultaneously.

<br/>

## Problem it solves

Have you ever been in a situation where you need to add a global loader/spinner to any side effect that you process using third-party libraries such as Redux and some kind of library for asynchronous processing, for example, redux-saga / redux-thunk / promise middlewares?

Why is that bad?

- It is very unpleasant to create separately for this state and add start and end actions for these actions to each request.
- This is an open place to make mistakes because it's very easy to forget to add or remove these actions.
- It needs to be supported and somehow live with it.

Well, `redux-pending-middleware` does this from scratch:

- tracks your asynchronous code
- collects them in a bunch
- efficiently calculates active pending effects
- provides a selector for information about the current state of application loading
- available for debug in redux-devtools
- independent of a particular asynchronous processing solution. Can be used simultaneously with `redux-saga` and `redux-toolkit`
- replaces `redux-thunk` in the matters of side effects (not actions chaining) and `redux-promise-middleware` (essentially uses it out of the box)

## Quick start

### Installation

```shell script
npm install redux-pending-middleware
```

### Extend reducers

`redux-pending-middleware` provides its own state for storing active effects (pending promise phase).

```javascript
import { combineReducers } from 'redux';
import { insertPending } from 'redux-pending-middleware';

import { planetReducer as planet } from './planetReducer';
import { universeReducer as universe } from './universeReducer';

export const rootReducer = combineReducers(
  insertPending({
    planet,
    universe
  })
);
```

### Configuration

Depending on what you use in the project, import into the project. Now let's dwell on this in more detail.

- ### [redux-toolkit](https://github.com/reduxjs/redux-toolkit)

This approach is simplest and clear. Just add the middleware and use your regular toolkit async actions as usual.

```javascript
import { configureStore, getDefaultMiddleware } from '@reduxjs/toolkit';
import { reduxPendingToolkitMiddleware } from 'redux-pending-middleware';
import { rootReducer as reducer } from './root.reducer';

const defaultMiddlewares = getDefaultMiddleware();
const middleware = [reduxPendingToolkitMiddleware, ...defaultMiddlewares];

export const store = configureStore({ reducer, middleware });
```

- ### [redux-saga](https://github.com/redux-saga/redux-saga)

If your project uses `redux-saga` no additional configuration needed.

This approach is that you need to wrap the saga worker.
This allows to track the start and the end of each effect.

```javascript
import { trackWorker } from 'redux-pending-middleware';
import { call, put, takeEvery } from '@redux-saga/core/effects';

function* getPlanets() {
  yield takeEvery(getPlanetsRequest.type, trackWorker(handleGetPlanets));
}

function* handleGetPlanets() {
  const planets = yield call(Api.getPlanets);
  yield put(getPlanetsCompleted(planets));
}
```

This approach successfully combined with custom wrappers on top of the worker, for example, error handling.

```javascript
const workerWrapper = worker => {
  return trackWorker(customWrapper);

  function* customWrapper(...args) {
    try {
      yield* worker(...args);
    } catch (error) {
      yield put(setFetchError(error));
    }
  }
};
```

- ### [redux-thunk](https://github.com/reduxjs/redux-thunk) / [redux-promise-middleware](https://github.com/pburtchaell/redux-promise-middleware)

Ok, here I need to explain the problem a bit

It’s not entirely true this package supports `redux-thunk`, but the truth is that you can forward promises to payload.
That is the way `redux-promise-middleware` does. At the moment, this library completely replaces `redux-promise-middleware`.
In the plans, through the collaboration, expand the API of `redux-promise-middleware` in order to reuse their code.

For details, you can go to read the documentation of `redux-promise-middleware` about how this works.

In short, everything is quite simple.
You pass Promise as payload and we will have stateful types inside the reducer.
Let's say we have action type `GET_PLANETS`, so when we call our action with a type and a promise in the payload, it first triggers a reducer with `GET_PLANETS_PENDING`.
Then, when our promise resolved, we will have `GET_PLANETS_FULFILLED` type inside the reducer, and a value of resolved promise as a payload.
But, if an error occurs in our promise, then we get the type `GET_PLANETS_REJECTED` with a reason within property payload.

```javascript
import { configureStore, getDefaultMiddleware } from '@reduxjs/toolkit';
import { reduxPendingPromiseMiddleware } from 'redux-pending-middleware';
import { rootReducer as reducer } from './root.reducer';

const defaultMiddlewares = getDefaultMiddleware();
const middleware = [reduxPendingPromiseMiddleware, ...defaultMiddlewares];

export const store = configureStore({ reducer, middleware });

/**
 * somewhere in the /src
 * saga usage example with trackWorker
 */
function getPlanets() {
  return {
    type: 'GET_PLANETS',
    payload: fetch('planets')
  };
}
```

### Connecting the dots

For everything to work at the same time, you need to use all the previous steps

```javascript
import { configureStore, getDefaultMiddleware } from '@reduxjs/toolkit';
import {
  reduxPendingPromiseMiddleware,
  reduxPendingToolkitMiddleware,
  trackWorker
} from 'redux-pending-middleware';
import createSagaMiddleware from '@redux-saga/core';
import { call, put, takeEvery } from '@redux-saga/core/effects';
import { rootReducer as reducer } from './root.reducer';
import { rootSaga } from './root.saga';

const defaultMiddlewares = getDefaultMiddleware();
const sagaMiddleware = createSagaMiddleware();
const middleware = [
  reduxPendingPromiseMiddleware,
  reduxPendingToolkitMiddleware,
  sagaMiddleware,
  ...defaultMiddlewares
];

export const store = configureStore({ reducer, middleware });

sagaMiddleware.run(rootSaga);

/**
 * somewhere in the /src
 * saga usage example with trackWorker
 */
function* getPlanets() {
  yield takeEvery(getPlanetsRequest.type, trackWorker(handleGetPlanets));
}

function* handleGetPlanets() {
  const planets = yield call(Api.getPlanets);
  yield put(getPlanetsCompleted(planets));
}
```

<br/>

### Selector

Just a regular usage of redux selectors

```javascript
import React from 'react';
import { useSelector } from 'react-redux';
import { selectIsPending } from 'redux-pending-middleware';

import { YourApplication } from './YourApplication';
import { AppLoader } from './App.loader';

export const App = () => {
  const isPending = useSelector(selectIsPending);

  return isPending ? <AppLoader /> : <YourApplication />;
};
```

<br/>

### Contributing

Contributions are welcome. For major changes, please open an issue first to discuss what you would like to change.

If you made a PR, make sure to update tests as appropriate and keep the examples consistent.

<br/>

### Contact

Please reach me out if you have any questions or comments.

- [GitHub](https://github.com/maktarsis)
- [Twitter](https://twitter.com/maktarsis)

<br/>

### References

I find these packages useful and similar for this one. So, it's important to mention them here.

- [redux-pending](https://www.npmjs.com/package/redux-pending)
- [redux-pender](https://www.npmjs.com/package/redux-pender)
- [redux-promise-middleware](https://www.npmjs.com/package/redux-promise-middleware)

The main reason why I didn’t choose them: they do one thing, and it’s impossible to add something second to them.

<br/>

### License

This project is [MIT](https://choosealicense.com/licenses/mit/) licensed.

<br/>

---
_Source: https://npm.io/package/redux-pending-middleware · Machine-readable twin of the npm.io package page. Health data is recomputed on every publish._
