redux-supermodel
Advanced tools
Comparing version 0.4.0 to 0.5.0
@@ -82,3 +82,3 @@ 'use strict'; | ||
const requestUrl = getResourceUrl(data); | ||
let config = _extends({}, rest, { data: data }); | ||
let config = _extends({}, rest, { url: requestUrl, method: method, data: data }); | ||
if (before) { | ||
@@ -88,3 +88,3 @@ config = before(config) || config; | ||
const payload = agent[method](requestUrl, config); | ||
const payload = agent(config); | ||
@@ -94,3 +94,3 @@ return { | ||
payload: payload, | ||
meta: { action: action, method: method, url: requestUrl, resourceName: resourceName, definition: definition } | ||
meta: { action: action, method: method, url: requestUrl, resourceName: resourceName, inputData: data, definition: definition } | ||
}; | ||
@@ -97,0 +97,0 @@ }; |
@@ -10,2 +10,9 @@ 'use strict'; | ||
exports.default = reducer; | ||
var _defaultTransform = require('./defaultTransform'); | ||
var _defaultTransform2 = _interopRequireDefault(_defaultTransform); | ||
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } | ||
const initialState = {}; | ||
@@ -46,3 +53,10 @@ | ||
const previous = state[meta.resourceName] && state[meta.resourceName].payload; | ||
const resource = { initialized: true, busy: true, payload: payload, previous: previous }; | ||
const transform = meta.definition.transform || _defaultTransform2.default; | ||
const resource = { | ||
initialized: true, | ||
busy: true, | ||
payload: transform(payload, previous, false, meta), | ||
previous: previous | ||
}; | ||
return _extends({}, state, { [meta.resourceName]: resource }); | ||
@@ -53,3 +67,11 @@ } | ||
{ | ||
const resource = { initialized: true, busy: false, payload: payload, previous: null }; | ||
const previousState = state[meta.resourceName] && state[meta.resourceName]; | ||
const transform = meta.definition.transform || _defaultTransform2.default; | ||
const resource = { | ||
initialized: true, | ||
busy: false, | ||
payload: transform(payload, previousState.payload, true, meta), | ||
previous: null | ||
}; | ||
return _extends({}, state, { [meta.resourceName]: resource }); | ||
@@ -60,4 +82,11 @@ } | ||
{ | ||
const previous = state[meta.resourceName] && state[meta.resourceName].previous; | ||
const resource = { initialized: true, busy: false, payload: previous, previous: null, error: payload }; | ||
const previousState = state[meta.resourceName] && state[meta.resourceName]; | ||
const resource = { | ||
initialized: true, | ||
busy: false, | ||
payload: previousState.payload, | ||
previous: null, | ||
error: payload | ||
}; | ||
return _extends({}, state, { [meta.resourceName]: resource }); | ||
@@ -64,0 +93,0 @@ } |
{ | ||
"name": "redux-supermodel", | ||
"version": "0.4.0", | ||
"version": "0.5.0", | ||
"description": "A package of action creator functions and reducers that deal with the state management of REST-like APIs for you... all you need is a URL!", | ||
@@ -33,2 +33,3 @@ "repository": "https://github.com/MrLeebo/redux-supermodel", | ||
"bdd-lazy-var": "^1.2.0", | ||
"body-parser": "^1.16.0", | ||
"enzyme": "^2.7.0", | ||
@@ -35,0 +36,0 @@ "eslint": "^3.13.1", |
# redux-supermodel | ||
[![Codacy Badge](https://api.codacy.com/project/badge/Grade/13429c5aaf274e1189e839675cb31969)](https://www.codacy.com/app/MrLeebo/redux-supermodel?utm_source=github.com&utm_medium=referral&utm_content=MrLeebo/redux-supermodel&utm_campaign=badger) | ||
Streamline the effort it takes for you to communicate between your [Redux](http://redux.js.org/) Store and a REST-like API. This is a package of action creator functions and reducers built with [axios](https://github.com/mzabriskie/axios) and [redux-promise-middleware](https://github.com/pburtchaell/redux-promise-middleware) that handle the resource state management for you... all you need is a URL! | ||
@@ -33,3 +35,3 @@ | ||
function MyComponent ({blogs, createBlog}) { | ||
const { ready, error, payload } = blogs; | ||
const { ready, error, payload } = blogs | ||
@@ -84,8 +86,8 @@ if (!ready) return <div className="loading">Please wait...</div> | ||
import { createStore, applyMiddleware, compose, combineReducers } from 'redux'; | ||
import promiseMiddleware from 'redux-promise-middleware'; | ||
import { createStore, applyMiddleware, compose, combineReducers } from 'redux' | ||
import promiseMiddleware from 'redux-promise-middleware' | ||
import { reducer as resource } from 'redux-supermodel' | ||
const rootReducer = combineReducers({ resource }); | ||
export default compose(applyMiddleware(promiseMiddleware()))(createStore)(rootReducer); | ||
const rootReducer = combineReducers({ resource }) | ||
export default compose(applyMiddleware(promiseMiddleware()))(createStore)(rootReducer) | ||
``` | ||
@@ -159,3 +161,4 @@ | ||
- `idAttribute : string` Defaults to "id" but you can change it if your resource has another identifier | ||
- `defaultPayload : anything` Sets the payload for before the resource has received anything from the server. Otherwise the payload will be `undefined` | ||
- `defaultPayload : any` Sets the payload for before the resource has received anything from the server. Otherwise the payload will be `undefined` | ||
- `transform : function(state, isFulfilled, meta) => nextState` When your resource is about to receive data, you may include a transform function to describe how you want to store that data. The default behavior is an identity function, whatever data gets received is what gets stored in the state. | ||
@@ -194,3 +197,3 @@ #### Building URLs | ||
### `resource(state, options) => object` State To Props Function | ||
#### `resource(state, options) => object` State To Props Function | ||
@@ -218,6 +221,66 @@ ```js | ||
#### Optimistic Updates | ||
#### Transformations | ||
When an AJAX request is dispatched, the payload is optimistically updated with the input data. The original payload data is copied to the `previous` property. If the request succeeds, the new data from the server will overwrite the `payload`. If the request fails, the `previous` value will overwrite the `payload` and the response from the server will be stored in the `error` property. | ||
You can control how the server's response to your AJAX request gets stored in your resource's state by defining a transform function. | ||
The transform function has the following signature: | ||
```js | ||
function transform (state, previousState, isFulfilled, meta) => nextState | ||
``` | ||
These are the parameters you will receive | ||
- `payload : any` The new payload of the resource. If `isFulfilled` is true, this will be the response from the server, otherwise it will be the input data from the request | ||
- `previous : any` The old payload of the resource | ||
- `isFulfilled : bool` True if the request has been fulfilled (i.e. the data came from the server). Otherwise the request is still pending and `state` contains the input data sent to the server. | ||
- `meta : object` The action metadata | ||
##### Optimistic Updates | ||
When an AJAX request is dispatched, the current state of the resource does not change until the server responds. For some applications, such as form-bound models, you may want to update the state optimistically with the request data before the server response has been fulfilled. You can implement optimistic updates by defining the transform function as a simple identity function: | ||
```js | ||
const optimisticUpdates = x => x | ||
blogs = client('blogs', { transform: optimisticUpdates }) | ||
``` | ||
##### Deleting an item from an index by marking it | ||
Many REST-like endpoints will respond to a DELETE action with a `204 No Content` response, but you probably don't want to replace your resource payload with no content. One thing you can do is modify your resource payload in redux with a `deleted: true` value instead of removing it entirely. You can use a transform function to do that. | ||
```js | ||
function markDeleted (payload, previous, isFulfilled, meta) { | ||
// Unless you want to use Optimistic Updates, keep the previous | ||
// payload until the request is fulfilled. | ||
if (!isFulfilled) return previous | ||
// Instead of deleting the resource state from our Redux store | ||
// outright, copy the previous state and add the "deleted" flag | ||
// so it can be displayed as such in the UI (e.g. with a | ||
// strikethrough or something) | ||
if (meta.action == 'destroy') { | ||
const { id } = payload | ||
let { data } = previous | ||
const index = data && data.findIndex(x => x.id === id) | ||
if (index >= 0) { | ||
// Make a copy of the array because we don't want to modify | ||
// the existing reference | ||
data = data.slice(0) | ||
data[index] = { ...data[index], deleted: true } | ||
return { ...previous, data } | ||
} | ||
return previous | ||
} | ||
// For all other cases, take the new payload | ||
return payload | ||
} | ||
blogs = client('blogs', { transform: markDeleted }) | ||
``` | ||
### `resource` Action Creators | ||
@@ -224,0 +287,0 @@ |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
23943
10
214
321
27