# redux-promise-middleware-actions

> Redux action creator for making async actions with redux-promise-middleware

Latest version **3.1.0** (published 2021-02-11) · MIT license · 0 weekly downloads

## Install

```sh
npm install redux-promise-middleware-actions
pnpm add redux-promise-middleware-actions
yarn add redux-promise-middleware-actions
bun add redux-promise-middleware-actions
```

## Health

**Score 25/100 (F)** — status: abandoned.

Positive: has types; no vulnerabilities; high quality score.

Warnings: low downloads; no esm support.

Negative: abandoned; low maintenance score.

## Facts

| | |
|---|---|
| Version | 3.1.0 |
| Published | 2021-02-11 |
| First published | 2018-07-22 |
| Weekly downloads | 0 |
| License | MIT |
| TypeScript types | bundled |
| Module format | CommonJS |
| Dependencies | 1 |
| Unpacked size | 43.3 KB |
| Known vulnerabilities | 0 |
| Install scripts | no |
| GitHub stars | 29 |
| Author | Ole Michelsen |
| Maintainers | omichelsen |
| Keywords | redux, actions, promise, async |

## Links

- npm: https://www.npmjs.com/package/redux-promise-middleware-actions
- Repository: https://github.com/omichelsen/redux-promise-middleware-actions
- Homepage: https://github.com/omichelsen/redux-promise-middleware-actions#readme
- Issues: https://github.com/omichelsen/redux-promise-middleware-actions/issues
- npm.io page: https://npm.io/package/redux-promise-middleware-actions

## Dependencies (1)

- [tslib](https://npm.io/package/tslib.md) ^2.1.0

## Alternatives

- [promise-throttle](https://npm.io/package/promise-throttle.md) — 44.2K weekly downloads
- [@commercetools/sync-actions](https://npm.io/package/@commercetools/sync-actions.md) — 25.1K weekly downloads
- [cwait](https://npm.io/package/cwait.md) — 21.4K weekly downloads
- [@ledgerhq/hw-app-cosmos](https://npm.io/package/@ledgerhq/hw-app-cosmos.md) — 4.2K weekly downloads
- [@financial-times/o-loading](https://npm.io/package/@financial-times/o-loading.md) — 2.8K weekly downloads

## Recent versions

- 3.1.0 (latest) — 2021-02-11
- 3.0.1 — 2019-08-24
- 3.0.0 — 2019-08-23
- 2.2.0 — 2019-08-23
- 2.1.0 — 2018-08-16
- 2.0.0 — 2018-08-16
- 1.0.0 — 2018-07-22

## README

# redux-promise-middleware-actions

[![Build Status](https://img.shields.io/travis/omichelsen/redux-promise-middleware-actions/master.svg)](https://travis-ci.org/omichelsen/redux-promise-middleware-actions)
[![Coverage Status](https://coveralls.io/repos/omichelsen/redux-promise-middleware-actions/badge.svg?branch=master&service=github)](https://coveralls.io/github/omichelsen/redux-promise-middleware-actions?branch=master)
[![npm bundle size (minified + gzip)](https://img.shields.io/bundlephobia/minzip/redux-promise-middleware-actions.svg)](https://bundlephobia.com/result?p=redux-promise-middleware-actions)

Create Redux actions with a `type` and `payload` in a standardized way. Inspired by [redux-actions](https://www.npmjs.com/package/redux-actions) but simpler and with special support for asynchronous actions (promises).

Has no dependencies and is tiny (~680 bytes gzipped). First class TypeScript support.

Works with [redux-promise-middleware](https://www.npmjs.com/package/redux-promise-middleware) to handle asynchronous actions by dispatching `pending`, `fulfilled` and `rejected` events based on the state of the input promise.

Goals of this library:

* Reference action creators directly - no need to maintain an action type enum/list
* Automatically generate actions for pending, fulfilled and rejected outcomes of a promise payload
* Have statically typed access to all action types - no need to manually add a type suffix like "_PENDING"
* TypeScript support so asynchronous actions can't be confused for normal synchronous actions

Note: If you are using TypeScript this library requires TypeScript 3. For TypeScript 2 use version 1 of this library.

## Installation

You need to install this library as well as [redux-promise-middleware](https://www.npmjs.com/package/redux-promise-middleware).

```
npm install redux-promise-middleware-actions redux-promise-middleware
```

Include redux-promise-middleware when you create your store:

```js
import promiseMiddleware from 'redux-promise-middleware';

composeStoreWithMiddleware = applyMiddleware(
  promiseMiddleware,
)(createStore);
```
NOTE: This library is *not* yet compatible with the `promiseTypeSuffixes` option of `redux-promise-middleware`

## Usage

### Synchronous action

Synchronous actions works exactly like redux-actions. You supply a function that returns whatever payload the action should have (if any).

```js
import { createAction } from 'redux-promise-middleware-actions';

export const foo = createAction('FOO', (num) => num);

dispatch(foo(5)); // { type: 'FOO', payload: 5 }
```

When handling the action in a reducer, you simply cast the action function to a string to return the type. This ensures type safety (no spelling errors) and you can use code navigation to find all uses of an action.

```js
const fooType = foo.toString(); // 'FOO'
```

### Asynchronous action

When you create an asynchronous action you need to return a promise payload. If your action is called `FOO` the following events will be dispatched:

1. `FOO_PENDING` is dispatched immediately
2. `FOO_FULFILLED` is dispatched when the promise is resolved
    * ... or `FOO_REJECTED` is dispatched instead if the promise is rejected

```js
import { createAsyncAction } from 'redux-promise-middleware-actions';

export const fetchData = createAsyncAction('FETCH_DATA', async () => {
  const res = await fetch(...);
  return res.json();
});

dispatch(fetchData()); // { type: 'FETCH_DATA_PENDING' }
```

An async action function has three properties to access the possible outcome actions: `pending`, `fulfilled` and `rejected`. You can dispatch them directly (in tests etc.):

```js
dispatch(fetchData.pending());          // { type: 'FETCH_DATA_PENDING' }
dispacth(fetchData.fulfilled(payload)); // { type: 'FETCH_DATA_FULFILLED', payload: ... }
dispacth(fetchData.rejected(err));      // { type: 'FETCH_DATA_REJECTED', payload: err, error: true }
```

But normally you only need them when you are writing reducers:

```js
case fetchData.pending.toString():   // 'FETCH_DATA_PENDING'
case fetchData.fulfilled.toString(): // 'FETCH_DATA_FULFILLED'
case fetchData.rejected.toString():  // 'FETCH_DATA_REJECTED'
```

Note that if you try and use the base function in a reducer, an error will be thrown to ensure you are not listening for an action that will never happen:

```js
case fetchData.toString(): // throws an error
```

### Reducer

To create a type safe reducer, `createReducer` takes a list of handlers that accept one or more actions and returns the new state. You can use it with both synchronous and asynchronous action creators.

#### `createReducer(defaultState, handlerMapsCreator)`

```js
import { createAsyncAction, createReducer } from 'redux-promise-middleware-actions';

const fetchData = createAsyncAction('GET', () => fetch(...));

const defaultState = {};

const reducer = createReducer(defaultState, (handleAction) => [
  handleAction(fetchData.pending, (state) => ({ ...state, pending: true })),
  handleAction(fetchData.fulfilled, (state, { payload }) => ({ ...state, pending: false, data: payload })),
  handleAction(fetchData.rejected, (state, { payload }) => ({ ...state, pending: false, error: payload })),
]);

reducer(undefined, fetchData()); // { pending: true, data: ..., error: ... }
```

#### `asyncReducer(asyncActionCreator)`

It can get tedious writing the same reducer for every single async action so we've included a simple reducer that does the same as the example above:

```js
import { asyncReducer } from 'redux-promise-middleware-actions';

const fetchData = createAsyncAction('GET', () => fetch(...));
const fetchReducer = asyncReducer(fetchData);

fetchReducer() // { data?: Payload, error?: Error, pending?: boolean }
```

You can also combine it with an existing reducer:

```js
export default (state, action) => {
  const newState = fetchReducer(state, action);

  switch (action.type) {
    case 'SOME_OTHER_ACTION':
      return { ... };
    default:
      return newState;
  }
};
```

### Metadata

You can add metadata to any action by supplying an additional metadata creator function. The metadata creator will receive the same arguments as the payload creator:

#### `createAction(type, payloadCreator, metadataCreator)`

```js
const foo = createAction(
  'FOO',
  (num) => num,
  (num) => num + num
);

dispatch(foo(5)); // { type: 'FOO', meta: 10, payload: 5 }
```

#### `createAsyncAction(type, payloadCreator, metadataCreator)`

```js
const fetchData = createAsyncAction(
  'FETCH_DATA',
  (n: number) => fetch(...),
  (n: number) => ({ n })
);

dispatch(fetchData(42));
// { type: 'FETCH_DATA_PENDING', meta: { n: 42 } }
// { type: 'FETCH_DATA_FULFILLED', meta: { n: 42 }, payload: Promise<...> }
// { type: 'FETCH_DATA_REJECTED', meta: { n: 42 }, payload: Error(...) }
```

### Custome Type Delimiters

You can specify a different type delimiter for your async actions:

#### `createAsyncAction(type, payloadCreator, metadataCreator, options)`

```js
const foo = createAsyncAction(
  'FETCH_DATA',
  (n: number) => fetch(num),
  undefined,
  { promiseTypeDelimiter: '/' }
);

dispatch(foo());
// { type: 'FETCH_DATA/PENDING' }
// { type: 'FETCH_DATA/FULFILLED', payload: ... }
// { type: 'FETCH_DATA/REJECTED', payload: ... }
```

## Acknowledgements

Thanks to [Deox](https://github.com/thebrodmann/deox/) for a lot of inspiration for the TypeScript types.

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