Function to create reducer enhancers (higher order reducers) that allow to add pre- and post-processing, handling arrays of actions, filtering and transforming of actions and state.
- Batch processing of actions by creating special
extraAction
. - Skip processing of actions that do not conform to some conditions (
filterAction
andskipFalsyAction
options). - Prepare actions for processing (
prepareAction
andtransformAction
options). - Run some code and modify state before and/or after source reducer (
prereduce
andpostreduce
options). - Pass additional arguments to reducer besides state and action (
reducerExtraArgs
option). - Monitor and save all processed actions and outcome states for debug purposes.
- Call a function at the start and the end of each processing step (
onStepStart
andonStepEnd
options).
Installation ↑
npm install extraduce
Use dist/extraduce.umd.development.js
or dist/extraduce.umd.production.min.js
(minified version).
Usage ↑
import * as extraduce from 'extraduce';
const extraduce = require('extraduce');
define(['path/to/dist/extraduce.umd.production.min.js'], function(extraduce) {
});
<script type="text/javascript" src="path/to/dist/extraduce.umd.production.min.js"></script>
<script type="text/javascript">
// extraduce is available via extraduce field of window object
</script>
Examples ↑
const initState = {
value: 0
};
function reducer(state, action) {
const { payload } = action;
switch (action.type) {
case 'INC_VALUE':
return Object.assign({}, state, {value: state.value + payload});
case 'SET_VALUE':
return Object.assign({}, state, {value: payload});
default:
return state;
}
}
const processStep = extraduce.ProcessStep;
const enhancedReducer = extraduce.extraduce(
reducer,
{
prepareAction(action) {
if (typeof action === 'number') {
return {
type: 'SET_VALUE',
payload: action
}
}
if (action && typeof action.payload === 'string') {
action.payload = Number(action.payload);
}
return action;
},
filterAction(action) {
const type = action && action.type;
const payload = action && action.payload;
return type && typeof type === 'string'
&& typeof payload === 'number' && ! isNaN(payload)
&& (payload !== 0 || type === 'SET_VALUE');
},
onStepStart(step, context) {
if (step === processStep.prepareAction) {
console.log('Action to be prepared -', context.action, '; current state -', context.state);
}
},
onStepEnd(step, context) {
if (step === processStep.reduce) {
console.log('Processed action -', context.action, '; current state -', context.state);
}
else if (step === processStep.process) {
console.log('Final state -', context.state);
}
}
}
);
const store = Redux.createStore(enhancedReducer, initState);
store.dispatch(extraduce.extraAction(
3,
{
type: 'INC_VALUE',
payload: 5
},
0,
{
type: 'INC_VALUE',
payload: 0
},
{
type: 'INC_VALUE',
payload: '-4'
},
false,
{
type: 'SET_VALUE',
payload: null
},
{
payload: 8
}
));
console.log('state:', store.getState()); // state: { value: -4 }
See additional examples in tests.
API ↑
Wraps passed reducer to add pre- and post-processing.
Arguments:
sourceReducer: Function
- Source reducer that should be wrapped.settings: object
- Optional settings to customize wrapping operation and features of created reducer.settings.data: any
(optional) - Any supplementary data that should be available in processing.settings.filterAction: Function
(optional) - Function that should be called to test whether current action is valid and should be passed for reducing.settings.historySize: number
(optional) - Size of list of fulfilled operations (processed actions).0
by default.settings.onStepEnd: Function
(optional) - Function that should be called at the end of each processing step.settings.onStepStart: Function
(optional) - Function that should be called at the start of each processing step.settings.postreduce: Function
(optional) - Function that should be called after source (wrapped) reducer.settings.postreduceValueIsState: boolean
(optional) - Whether result ofpostreduce
function should be used as new state in further processing.settings.prepareAction: Function
(optional) - Function that should be called to prepare current action for further processing before filtering.settings.prereduce: Function
(optional) - Function that should be called before source (wrapped) reducer.settings.prereduceValueIsState: boolean
(optional) - Whether result ofprereduce
function should be used as new state in further processing.settings.processActionArray: boolean
(optional) - Whether an array that is passed as action should be treated as list of actions that should be processed separately.true
by default.settings.reducerExtraArgs: any | any[]
(optional) - Supplementary arguments that should be passed into source (wrapped) reducer besides state and action. Or a function that returns such arguments.settings.skipFalsyAction: boolean
(optional) - Whether processing of an action that has a falsy value should be skipped.true
by default.settings.transformAction: Function
(optional) - Function that should be called to transform current valid action after filtering.
Returns new created reducer that can be used instead of source reducer.
Returns type of action that is used to wrap several actions to be processed.
Changes type of action that is used to wrap several actions to be processed.
Creates action that is used to wrap several actions to be processed.
Checks whether passed value represents an action that wraps several actions to be processed.
See docs
for details.
Related projects ↑
Contributing ↑
In lieu of a formal styleguide, take care to maintain the existing coding style. Add unit tests for any new or changed functionality. Lint and test your code.
License ↑
Copyright (c) 2020 Denis Sikuler
Licensed under the MIT license.