Ecosyste.ms: Awesome

An open API service indexing awesome lists of open source software.

Awesome Lists | Featured Topics | Projects

https://github.com/Brigad/redux-rest-easy

⛳ Redux/React/React Native framework handling network requests, state management, selectors, caching and much more
https://github.com/Brigad/redux-rest-easy

Last synced: 26 days ago
JSON representation

⛳ Redux/React/React Native framework handling network requests, state management, selectors, caching and much more

Awesome Lists containing this project

README

        

# ⛳ @brigad/redux-rest-easy

Redux/React/React Native framework handling network requests, state management, selectors, caching and much more

[![CircleCI][circle-ci-badge]][circle-ci]
[![Codecov][codecov-badge]][codecov]
[![version][version-badge]][package]
[![downloads][downloads-badge]][package]
[![MIT License][license-badge]][license]
[![All Contributors](https://img.shields.io/badge/all_contributors-6-orange.svg?style=flat-square)](#contributors)
[![PRs Welcome][prs-badge]][prs]
[![Code of Conduct][coc-badge]][coc]
[![code style: prettier][prettier-badge]][prettier]
[![semantic-release][semantic-release-badge]][semantic-release]
[![Star on GitHub][github-star-badge]][github-star]

## [Release article][release-article]

## Installation

```bash
yarn add @brigad/redux-rest-easy
```

Or, if you are using npm:

```bash
npm install --save @brigad/redux-rest-easy
```

## Problem

At Brigad, we have been extensively using redux and redux-thunk to perform network requests, and store/access the resulting data, and we always felt some pain points, or at least like there were things we could do better:

- We were often **copying/pasting a lot of code** (along with some logic regarding caching, hooks, etc) from one file to another each time we would create a new resource or action
- Our state was **not organized at all**, and accessing it was messy and error-prone
- We had a huge **caching problem**: sometimes performing unnecessary requests, sometimes not performing requests which should have been
- We had no way to know if **a given component was performing an action**, we only knew if an action was being performed on a given resource

## Solution

To solve the problems listed above, `redux-rest-easy` **generates actions, reducers, and selectors**, and also **manages the state's data and metadata** for your **network requests**. It is easy to use, and to observe via the Redux Devtools.

It also provides **sensible defaults**, allowing you to use it with **almost no configuration**, but also to **customize** anything you would like.

And the cherry on the top: it works seamlessly with [redux-offline](https://github.com/redux-offline/redux-offline) and [redux-persist](https://github.com/rt2zz/redux-persist)!

[Scroll down](#minimal-example) for a small example, or [browse the documentation](#api) to get started! To learn more about the problem and solution, you can also read the [release article][release-article].

## API

```js
import {
createResource,
reducer,
connect,
reset,
initializeNetworkHelpers,
getPersistableState,
} from '@brigad/redux-rest-easy';
```

- [createResource](./docs/api/createResource.md) - easily generate then export your actions and selectors from one file
- [reducer](./docs/api/reducer.md) - plug a single reducer to your state, we handle the rest
- [connect](./docs/api/connect.md) - connect your components to the state so the magic can happen
- [reset](./docs/api/reset.md) - reset `redux-rest-easy`'s whole state (you can reset parts of the state with actions generated by `createResource`)
- [initializeNetworkHelpers](./docs/api/initializeNetworkHelpers.md) - provide your own network handlers (optional, fallback to included defaults)
- [getPersistableState](./docs/api/getPersistableState.md) - transform the state before storing it, in order to later persist it (using [redux-offline](https://github.com/redux-offline/redux-offline), [redux-persist](https://github.com/rt2zz/redux-persist), or friends)

## Internals

- [Actions configuration](./docs/api/createResource/actionsConfig.md) - defining your actions with `createResource`
- [Actions](./docs/api/createResource/actions.md) - actions generated by `createResource`
- [Selectors](./docs/api/createResource/selectors.md) - selectors generated by `createResource`

## Core principles

1. [Preflight checks](./docs/principles/preflight.md)
2. [Actions](./docs/principles/actions.md)
3. [Reducers](./docs/principles/reducers.md)
4. [Selectors](./docs/principles/selectors.md)

## Minimal Example

```js
// users.js

import { createResource } from '@brigad/redux-rest-easy';

const users = createResource('users')({
retrieve: {
method: 'GET',
url: 'https://my-api.com/users',
afterHook: () => console.log('Users retrieved successfully'),
},
});

const {
actions: { retrieve: retrieveUsers },
selectors: {
resource: { getResource: getUsers },
retrieve: {
request: { isPerforming: isRetrievingUsers },
},
},
} = users;

export { retrieveUsers, getUsers, isRetrievingUsers };
```

```js
// reducers.js

import { reducer } from '@brigad/redux-rest-easy';

const reducers = combineReducers({
restEasy: reducer,
});
```

```js
// UsersList.js

import React, { Component } from 'react';
import { connect } from '@brigad/redux-rest-easy';
import {
retrieveUsers,
getUsers,
isRetrievingUsers,
} from './redux-rest-easy/users';

class UsersList extends Component {
state = {
error: false,
};

componentDidMount() {
this.props.retrieveUsers(this.onSuccess, this.onError);
}

onSuccess = () => {
this.setState({ error: false });
};

onError = () => {
this.setState({ error: true });
};

render() {
if (this.props.isRetrievingUsers) {
return

{'Loading...'}
;
}

if (this.state.error) {
return (

{'There seems to be a problem... A network error occured.'}

);
}

return ;
}
}

const mapStateToProps = state => ({
users: getUsers(state),
isRetrievingUsers: isRetrievingUsers(state),
});

const mapDispatchToProps = dispatch => ({
retrieveUsers: (onSuccess, onError) =>
dispatch(retrieveUsers({ onSuccess, onError })),
});

export default connect(
mapStateToProps,
mapDispatchToProps,
)(ConnectedComponent);
```

## Peer dependencies

Redux-rest-easy assumes you are using [react][react] (or [react-native][react-native]) and [react-redux][react-redux].

Redux-rest-easy also uses [redux-thunk][redux-thunk] under the hood, to handle async actions, and therefore requires you to use redux-thunk's middleware in your store. If you are already using redux-thunk, then you have nothing more to do. Else, follow [redux-thunk's docs][redux-thunk-installation] for a quick setup.

## Examples

### [Simple Example](https://codesandbox.io/s/ko7xm5wxy7)

Displays a list of users and allows to create new ones.

### Pagination (TODO, coming soon)

Displays a paginated list, with seamless query-based selectors and cache.

### Data invalidation (TODO, coming soon)

Invalidates store data after a successful POST request

### Multiple requests (e.g. S3 signed upload) (TODO, coming soon)

Performs multiple requests in beforeHook before the final one, to upload a signed file to S3.

### Cache hints (TODO, coming soon)

Makes use of cache hints to customize the built-in cache.

### Store persistence (TODO, coming soon)

Introduces store persistence in the "Pagination" example, so that data persists after the page is refreshed.

## Contributors

Thanks goes to these people ([emoji key][emojis]):

| [
Adrien HARNAY](https://adrien.harnay.me)
[📝](#blog-adrienharnay "Blogposts") [💻](https://github.com/Brigad/redux-rest-easy/commits?author=adrienharnay "Code") [📖](https://github.com/Brigad/redux-rest-easy/commits?author=adrienharnay "Documentation") [🤔](#ideas-adrienharnay "Ideas, Planning, & Feedback") [🚇](#infra-adrienharnay "Infrastructure (Hosting, Build-Tools, etc)") [👀](#review-adrienharnay "Reviewed Pull Requests") [⚠️](https://github.com/Brigad/redux-rest-easy/commits?author=adrienharnay "Tests") | [
Thibault Malbranche](https://github.com/Titozzz)
[🐛](https://github.com/Brigad/redux-rest-easy/issues?q=author%3ATitozzz "Bug reports") [💻](https://github.com/Brigad/redux-rest-easy/commits?author=Titozzz "Code") [🤔](#ideas-Titozzz "Ideas, Planning, & Feedback") [👀](#review-Titozzz "Reviewed Pull Requests") | [
Grisha Ghukasyan](https://github.com/eole1712)
[🤔](#ideas-eole1712 "Ideas, Planning, & Feedback") | [
Aymeric Beaumet](https://aymericbeaumet.com)
[🤔](#ideas-aymericbeaumet "Ideas, Planning, & Feedback") | [
Jess](https://github.com/Pinesy)
[🐛](https://github.com/Brigad/redux-rest-easy/issues?q=author%3APinesy "Bug reports") [📖](https://github.com/Brigad/redux-rest-easy/commits?author=Pinesy "Documentation") | [
Matt Labrum](https://github.com/mlabrum)
[💻](https://github.com/Brigad/redux-rest-easy/commits?author=mlabrum "Code") |
| :---: | :---: | :---: | :---: | :---: | :---: |

This project follows the [all-contributors][all-contributors] specification.
Contributions of any kind welcome!

[release-article]: https://engineering.brigad.co/introducing-redux-rest-easy-6e9a91af4f59
[circle-ci-badge]: https://img.shields.io/circleci/project/github/Brigad/redux-rest-easy/master.svg?style=flat-square&label=build
[circle-ci]: https://circleci.com/gh/Brigad/redux-rest-easy
[codecov-badge]: https://img.shields.io/codecov/c/github/Brigad/redux-rest-easy.svg
[codecov]: https://codecov.io/gh/Brigad/redux-rest-easy
[version-badge]: https://img.shields.io/npm/v/@brigad/redux-rest-easy.svg?style=flat-square
[downloads-badge]: https://img.shields.io/npm/dt/@brigad/redux-rest-easy.svg?style=flat-square
[package]: https://www.npmjs.com/package/@brigad/redux-rest-easy
[license-badge]: https://img.shields.io/npm/l/@brigad/redux-rest-easy.svg?style=flat-square
[license]: https://github.com/Brigad/redux-rest-easy/blob/master/LICENSE.md
[prs-badge]: https://img.shields.io/badge/PRs-welcome-brightgreen.svg?style=flat-square
[prs]: http://makeapullrequest.com
[coc-badge]: https://img.shields.io/badge/code%20of-conduct-ff69b4.svg?style=flat-square
[coc]: https://github.com/Brigad/redux-rest-easy/blob/master/CODE_OF_CONDUCT.md
[prettier-badge]: https://img.shields.io/badge/code_style-prettier-ff69b4.svg?style=flat-square
[prettier]: https://github.com/prettier/prettier
[semantic-release-badge]: https://img.shields.io/badge/%20%20%F0%9F%93%A6%F0%9F%9A%80-semantic--release-e10079.svg
[semantic-release]: https://github.com/semantic-release/semantic-release
[github-star-badge]: https://img.shields.io/github/stars/Brigad/redux-rest-easy.svg?style=social
[github-star]: https://github.com/Brigad/redux-rest-easy/stargazers
[react]: https://github.com/facebook/react
[react-native]: https://github.com/facebook/react-native
[react-redux]: https://github.com/reactjs/react-redux
[redux-thunk]: https://github.com/gaearon/redux-thunk
[redux-thunk-installation]: https://github.com/gaearon/redux-thunk#installation
[emojis]: https://github.com/kentcdodds/all-contributors#emoji-key
[all-contributors]: https://github.com/kentcdodds/all-contributors