UNPKG

6.09 kBMarkdownView Raw
1[![npm version](https://badge.fury.io/js/%40shoutem%2Fredux-io.svg)](https://badge.fury.io/js/%40shoutem%2Fredux-io)
2
3redux-io
4====================
5
6`redux-io` is library for data management of network data in `redux` and ease of data use in `react`. Consists of
7middleware, reducers, action creators and helpers that provide:
8
9- [JSON-API](http://jsonapi.org/)
10- normalized data in `redux`
11- async CRUD operations with `redux` actions
12- optimistic updates of redux
13- denormalizing data for easier use in `react`
14- data caching and supported compatibility with `reselect`
15- simple and expandable network resource configuration
16- data status, error handling and monitoring operations
17- [SOON] JSON payloads with normalizr schemas
18
19## Motivation
20
21Redux is a great library, but it’s not a framework. It’s based on simple concepts that enable the freedom to build,
22but without clear patterns. But how are you going to manage network data and organize it in store, make async requests,
23normalize data, handle errors, cache data, monitor data statuses? At Shoutem we developed platform based on `react`
24ecosystem in which we use `redux` for managing data. We learned a lot about problems and discovered practices that give
25answers to above questions. All that is used in development of `redux-io` library that we use everyday and enables us
26powerful data management.
27
28## Documentation
29
30- [API Reference](https://github.com/shoutem/redux-io/tree/develop/docs/api)
31
32## Getting started
33
34Install `redux-io`:
35
36```
37$ npm install --save @shoutem/redux-io
38```
39
40Import middlewares `apiMiddleware`, `apiStateMiddleware` and add them to your `createStore` in `applyMiddleware`
41function from `redux`. We are internally using [`redux-api-middleware@2.0.0-beta.1`]
42(https://github.com/agraboso/redux-api-middleware/tree/next) as library for async network requests,
43so that is the reason you need to add both middlewares respectively.
44
45Example:
46
47```js
48import { applyMiddleware, compose, createStore } from 'redux';
49import { apiMiddleware } from 'redux-api-middleware';
50import { apiStateMiddleware } from '@shoutem/redux-io';
51import createLogger from 'redux-logger';
52import thunk from 'redux-thunk';
53import reducer from './reducers'
54
55const logger = createLogger();
56
57const store = createStore(
58 reducer,
59 applyMiddleware(thunk, apiMiddleware, apiStateMiddleware, logger)
60);
61```
62
63And you are ready to start organizing state, configuring network resources, manage data with actions and use them in
64react components. Next section gives short intro in usage of redux-io in most common use cases.
65
66## Usage
67
68For example, you have [json-api](http://jsonapi.org/) API endpoint that enables you to fetch items of type `acme.items`.
69You want to get most popular items, so endpoint `http://api.test.com/items?sort=relevance` returns you list of items
70sorted by popularity:
71
72```json
73{
74 "data": [
75 {
76 "type": "acme.items",
77 "id": "1",
78 "attributes": {
79 "name": "Rocket",
80 }
81 },
82 {
83 "type": "acme.items",
84 "id": "2",
85 "attributes": {
86 "name": "Helmet",
87 }
88 },
89 ...
90 ]
91}
92```
93
94First you want to configure where fetched data will be placed in your state. Use `storage` as a normal reducer to define
95where in your state are instances of objects, and `collection` reducer to set place in the state for list holding ids
96of items that are popular. You are probably asking why do you need those two reducers, but idea is to keep data in redux
97state normalized. Normalization instances needs to be in one place in the state. However, you can reference it from
98mutliple parts in the state.
99
100```js
101import { storage, collection } from `redux-api-state`;
102
103combineReducers({
104 items: storage('acme.items'),
105 popularItems: collection('acme.items', 'popularItems'),
106})
107```
108
109After that, you only need to dispatch `find` action to fetch popular items from API. Find action is based on
110redux-api-middleware, and only needs to additional params `schema`, and `tag`. Schema defines in which `storage` will
111fetched data end up, and `tag` defines which `collection` will fetch ids of objects.
112
113```js
114import { find } from `redux-api-state`;
115
116const config = {
117 endpoint: 'http://api.test.com/items?sort=relevance',
118 headers: {
119 'Content-Type': 'application/vnd.api+json',
120 },
121};
122
123dispatch(find(config, 'acme.items', 'popularItems'));
124```
125
126Upon dispatch, `find` will configure action by redux-api-middleware specification, and redux-api-middleware will
127
1281. Dispatch REQUEST action
1292. Make GET request on http://api.test.com/items?sort=relevance
1303. If request is successful dispatch SUCCESS action
131
132You can see that it is by `redux-api-middleware` [lifecycle](www.test.com). After which redux-api-state will listen on
133SUCCESS action and will act as:
134
1351. Validate SUCCESS action
1362. Unpack payload
1373. For each item in data will dispatch OBJECT_FETCHED
1384. Storage reducer will listen for OBJECT_FETCH and add it into map in state
1395. Dispatch COLLECTION_FETCHED
1406. Collection reducer will listen for COLLECTION_FETCHED and add items id into list
1417. Call next(action) for success action from redux-api-middleware
142
143Storage reducer only adds an item if action is valid and schema value is equal to the action's schema. Collection
144reducer performs the same, but checks also `tag` value. That enable us to have multiple collections of objects, but only
145one storage with instances of objects. Here is the state after app finished fetching:
146
147```js
148state: {
149 items: {
150 1: {
151 "type": "acme.items",
152 "id": "1",
153 "attributes": {
154 "name": "Rocket",
155 }
156 },
157 2: {
158 "type": "acme.items",
159 "id": "2",
160 "attributes": {
161 "name": "Helmet",
162 }
163 },
164 },
165 popularItems: [1, 2, 3, ... ],
166}
167```
168
169## Tests
170
171```
172$ npm install && npm test
173```
174
175## Acknowledgements
176
177The package is based on concepts from [Željko Rumenjak](https://github.com/zrumenjak).