Skip to content

Commit

Permalink
add cooldux middleware
Browse files Browse the repository at this point in the history
  • Loading branch information
monteslu committed Jul 31, 2018
1 parent 4049197 commit 8fd7e42
Show file tree
Hide file tree
Showing 7 changed files with 2,148 additions and 108 deletions.
38 changes: 38 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -140,3 +140,41 @@ export function fetchDataB() {
export default reducerCombined;

```




## promiseMiddleware

You can optionally add the cooldux promise-aware middleware to redux to automatically handle dispatching the different parts of an asynchronous call.

Just apply promiseMiddleware:

```javascript
import { promiseMiddleware } from 'cooldux';
const store = createStore(reducers, applyMiddleware(promiseMiddleware));

```

Now this lets us shorten our previous example by not having to pass around the dispatch function normally required by redux-thunk:

```javascript

const { exampleAAction,
exampleBAction,
reducerCombined
} = combinedHandler(['exampleA', 'exampleB']);


export function fetchDataA() {
return exampleAAction(somePromiseAPI());
}

export function fetchDataB() {
return exampleBAction(someOtherAPI());
}

//this will run through all the reducers created
export default reducerCombined;

```
250 changes: 150 additions & 100 deletions index.js
Original file line number Diff line number Diff line change
@@ -1,109 +1,159 @@
(function(global, factory) {
typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) : typeof define === 'function' && define.amd ? define([ 'exports' ], factory) : factory(global.cooldux = {});
})(this, function(exports) {
'use strict';
var typeIndex = 0;
function createRandomType() {
typeIndex++;
return 'RAND_' + typeIndex + '_' + Math.random();
'use strict';

Object.defineProperty(exports, '__esModule', {
value: true
});

var typeIndex = 0;

function createRandomType() {
typeIndex++;
return 'RAND_' + typeIndex + '_' + Math.random();
}

function makeActionCreator(type) {
if (type === void 0) {
type = createRandomType();
}
function makeActionCreator(type) {
if (type === void 0) {
type = createRandomType();
}
var actionCreator = function(payload) {
return {
type: type,
payload: payload
};
var actionCreator = function(payload) {
return {
type: type,
payload: payload
};
actionCreator.type = type;
return actionCreator;
};
actionCreator.type = type;
return actionCreator;
}

var reset = makeActionCreator('cooldux-RESET');

function resetReducer(initialState, reducer) {
return function(state, action) {
return reset.type === action.type ? initialState : reducer(state, action);
};
}

function promiseHandler(type, options) {
if (options === void 0) {
options = {};
}
var reset = makeActionCreator('cooldux-RESET');
function resetReducer(initialState, reducer) {
return function(state, action) {
return reset.type === action.type ? initialState : reducer(state, action);
if (typeof options === 'string') {
options = {
namespace: options
};
}
function promiseHandler(type, options) {
if (options === void 0) {
options = {};
}
if (typeof options === 'string') {
options = {
namespace: options
};
}
var name = (options.namespace ? options.namespace + '-' : '') + type;
var initialState = {};
initialState[type] = null;
initialState[type + 'Pending'] = false;
initialState[type + 'Error'] = null;
var creators = {};
creators[type + 'InitialState'] = initialState;
creators[type + 'Start'] = makeActionCreator(name + '_Start');
creators[type + 'End'] = makeActionCreator(name + '_End');
creators[type + 'Error'] = makeActionCreator(name + '_Error');
creators[type + 'Handler'] = function(promise, dispatch) {
dispatch(creators[type + 'Start']());
return promise.then(function(result) {
dispatch(creators[type + 'End'](result));
return result;
}).catch(function(error) {
dispatch(creators[type + 'Error'](error));
if (options.throwErrors) {
throw error;
}
return null;
});
};
creators[type + 'Reducer'] = function(state, action) {
var obj, obj$1, obj$2;
state = state || initialState;
switch (action.type) {
case creators[type + 'Start'].type:
return Object.assign({}, state, (obj = {}, obj[type + 'Pending'] = true, obj[type + 'Error'] = null,
obj));

case creators[type + 'End'].type:
return Object.assign({}, state, (obj$1 = {}, obj$1[type + 'Pending'] = false, obj$1[type + 'Error'] = null,
obj$1[type] = action.payload, obj$1));

case creators[type + 'Error'].type:
return Object.assign({}, state, (obj$2 = {}, obj$2[type + 'Pending'] = false, obj$2[type + 'Error'] = action.payload,
obj$2));

default:
return state;
var name = (options.namespace ? options.namespace + '-' : '') + type;
var initialState = {};
initialState[type] = null;
initialState[type + 'Pending'] = false;
initialState[type + 'Error'] = null;
var creators = {};
creators[type + 'InitialState'] = initialState;
creators[type + 'Start'] = makeActionCreator(name + '_Start');
creators[type + 'End'] = makeActionCreator(name + '_End');
creators[type + 'Error'] = makeActionCreator(name + '_Error');
creators[type + 'Handler'] = function(promise, dispatch) {
dispatch(creators[type + 'Start']());
return promise.then(function(result) {
dispatch(creators[type + 'End'](result));
return result;
}).catch(function(error) {
dispatch(creators[type + 'Error'](error));
if (options.throwErrors) {
throw error;
}
return null;
});
};
creators[type + 'Action'] = function(promise) {
promise._cooldux = {
name: name,
options: options
};
return creators;
}
function combinedHandler(types, options) {
var handlers = {};
var initialState = types.reduce(function(state, type) {
var handler = promiseHandler(type, options);
Object.assign(handlers, handler);
Object.assign(state, handler[type + 'InitialState']);
return promise;
};
creators[type + 'Reducer'] = function(state, action) {
var obj, obj$1, obj$2, obj$3, obj$4, obj$5;
state = state || initialState;
switch (action.type) {
case creators[type + 'Start'].type:
return Object.assign({}, state, (obj = {}, obj[type + 'Pending'] = true, obj), (obj$1 = {},
obj$1[type + 'Error'] = null, obj$1));

case creators[type + 'End'].type:
return Object.assign({}, state, (obj$2 = {}, obj$2[type + 'Pending'] = false, obj$2), (obj$3 = {},
obj$3[type] = action.payload, obj$3));

case creators[type + 'Error'].type:
return Object.assign({}, state, (obj$4 = {}, obj$4[type + 'Pending'] = false, obj$4), (obj$5 = {},
obj$5[type + 'Error'] = action.payload, obj$5));

default:
return state;
}, {});
Object.assign(handlers, {
initialStateCombined: Object.assign({}, initialState),
reducerCombined: function(state, action) {
return types.reduce(function(state, type) {
return handlers[type + 'Reducer'](state, action);
}, Object.assign({}, state || initialState));
}
});
return handlers;
}
exports.makeActionCreator = makeActionCreator;
exports.reset = reset;
exports.resetReducer = resetReducer;
exports.promiseHandler = promiseHandler;
exports.combinedHandler = combinedHandler;
Object.defineProperty(exports, '__esModule', {
value: true
}
};
return creators;
}

function combinedHandler(types, options) {
var handlers = {};
var initialState = types.reduce(function(state, type) {
var handler = promiseHandler(type, options);
Object.assign(handlers, handler);
Object.assign(state, handler[type + 'InitialState']);
return state;
}, {});
Object.assign(handlers, {
initialStateCombined: Object.assign({}, initialState),
reducerCombined: function(state, action) {
return types.reduce(function(state, type) {
return handlers[type + 'Reducer'](state, action);
}, Object.assign({}, state || initialState));
}
});
});
return handlers;
}

var promiseMiddleware = function(ref) {
var dispatch = ref.dispatch;
return function(next) {
return function(action) {
if (action.then && action._cooldux) {
var _cooldux = action._cooldux;
dispatch({
type: _cooldux.name + '_Start'
});
return action.then(function(payload) {
dispatch({
type: _cooldux.name + '_End',
payload: payload
});
return payload;
}).catch(function(err) {
dispatch({
type: _cooldux.name + '_Error',
payload: err
});
if (_cooldux.options.throwErrors) {
throw err;
}
return null;
});
}
next(action);
return action;
};
};
};

exports.makeActionCreator = makeActionCreator;

exports.reset = reset;

exports.resetReducer = resetReducer;

exports.promiseHandler = promiseHandler;

exports.combinedHandler = combinedHandler;

exports.promiseMiddleware = promiseMiddleware;
43 changes: 38 additions & 5 deletions index.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -81,15 +81,19 @@ export function promiseHandler(type, options = {}) {
return null;
});
},
[type + 'Action']: (promise) => {
promise._cooldux = { name, options };
return promise;
},
[type + 'Reducer']: (state, action) => {
state = state || initialState;
switch (action.type) {
case creators[type + 'Start'].type:
return {...state, [type + 'Pending']: true, [type + 'Error']: null};
return Object.assign({}, state, {[type + 'Pending']: true}, {[type + 'Error']: null });
case creators[type + 'End'].type:
return {...state, [type + 'Pending']: false, [type + 'Error']: null, [type]: action.payload};
return Object.assign({}, state, {[type + 'Pending']: false}, {[type ]: action.payload });
case creators[type + 'Error'].type:
return {...state, [type + 'Pending']: false, [type + 'Error']: action.payload};
return Object.assign({}, state, {[type + 'Pending']: false}, {[type + 'Error']: action.payload });
default:
return state;
}
Expand All @@ -116,12 +120,41 @@ export function combinedHandler(types, options) {
return state;
}, {});
Object.assign(handlers, {
initialStateCombined: {...initialState},
initialStateCombined: Object.assign({}, initialState),
reducerCombined: (state, action) =>
types.reduce(
(state, type) => handlers[type + 'Reducer'](state, action),
{...(state || initialState)}
Object.assign({}, (state || initialState))
)
});
return handlers;
}

/**
* A middleware for redux that auto-dispatches cooldux actions from a cooldux promiseHandler.
*
* @param {Function} dispatch
*/
export const promiseMiddleware = ({ dispatch }) => {
return next => {
return action => {
if(action.then && action._cooldux) {
const { _cooldux } = action;
dispatch({type: _cooldux.name + '_Start'});
return action.then(payload => {
dispatch({type: _cooldux.name + '_End', payload});
return payload;
})
.catch(err => {
dispatch({type: _cooldux.name + '_Error', payload: err});
if(_cooldux.options.throwErrors) {
throw err;
}
return null;
});
}
next(action);
return action;
}
}
}
Loading

0 comments on commit 8fd7e42

Please sign in to comment.