├── package.json ├── LICENSE ├── index.js ├── readme.md └── test.js /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "create-reducer", 3 | "version": "1.0.1", 4 | "description": "Create reducer from object of action handlers, for use with redux.", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "node test.js" 8 | }, 9 | "author": "Nick Niemeir ", 10 | "license": "ISC", 11 | "repository": { 12 | "type": "git", 13 | "url": "https://github.com/nrn/create-reducer" 14 | }, 15 | "dependencies": {}, 16 | "devDependencies": { 17 | "tape": "^4.2.0" 18 | }, 19 | "keywords": [ 20 | "create", 21 | "compose", 22 | "store", 23 | "react", 24 | "reduce", 25 | "reducer", 26 | "redux" 27 | ] 28 | } 29 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2015 Nick Niemeir 2 | 3 | Permission to use, copy, modify, and/or distribute this software for any 4 | purpose with or without fee is hereby granted, provided that the above 5 | copyright notice and this permission notice appear in all copies. 6 | 7 | THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH 8 | REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY 9 | AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, 10 | INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM 11 | LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR 12 | OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 13 | PERFORMANCE OF THIS SOFTWARE. 14 | 15 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | createReducer.compose = compose 2 | 3 | module.exports = createReducer 4 | 5 | function createReducer (handlers, getInitialState) { 6 | if (typeof getInitialState !== 'function') { 7 | throw new Error('Must provide getInitialState function to be called when state is undefined.') 8 | } 9 | return function (state, action) { 10 | var handler = handlers[action.type] 11 | if (typeof state === 'undefined') { 12 | state = getInitialState(action) 13 | } 14 | return ( 15 | typeof handler === 'function' ? 16 | handler.call(handlers, state, action) : 17 | state 18 | ) 19 | } 20 | } 21 | 22 | function compose (fns) { 23 | return function (state, action) { 24 | return fns.reduce(function (last, fn) { 25 | return fn(last, action) 26 | }, state) 27 | } 28 | } 29 | 30 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | # create-reducer 2 | 3 | Create a redux reducer from an object of action handling functions, keyed 4 | by the actions they handle. Has `createReducer.compose(fns)` helper function 5 | to combine multiple action handlers into a single action. 6 | Big thanks to dlmanning, our conversations lead me here. 7 | 8 | ```javascript 9 | var createReducer = require('create-reducer') 10 | 11 | // setup handlers, object keys for action types 12 | var handlers = { 13 | add: add, 14 | multiply: multiply, 15 | // compose handler functions together for compound actions. 16 | addThenMultiply: createReducer.compose(add, multiply) 17 | } 18 | 19 | module.exports = createReducer(handlers, function () { 20 | return { num: 0 } 21 | }) 22 | 23 | // actual action handling functions, down out of the way. 24 | function add (state, action) { 25 | return { 26 | num: state.num + action.payload 27 | } 28 | } 29 | 30 | function multiply (state, action) { 31 | return { 32 | num: state.num * action.payload 33 | } 34 | } 35 | ``` 36 | -------------------------------------------------------------------------------- /test.js: -------------------------------------------------------------------------------- 1 | var createReducer = require('./index') 2 | var test = require('tape') 3 | 4 | // setup handlers, object keys for action types 5 | var handlers = { 6 | add: add, 7 | multiply: multiply, 8 | createSubtract: createSubtract, 9 | // compose handler functions together for compound actions. 10 | addThenMultiply: createReducer.compose([add, multiply]) 11 | } 12 | 13 | // create a reducer from the handlers, this is normaly what would be exported. 14 | var reducer = createReducer(handlers, function () { 15 | return { 16 | num: 0 17 | } 18 | }) 19 | 20 | // actual action handling functions, down out of the way. 21 | function add (state, action) { 22 | return { 23 | num: state.num + action.payload 24 | } 25 | } 26 | 27 | function multiply (state, action) { 28 | return { 29 | num: state.num * action.payload 30 | } 31 | } 32 | 33 | function createSubtract (state) { 34 | this.subtract = function (state, action) { 35 | return { 36 | num: state.num - action.payload 37 | } 38 | } 39 | return state 40 | } 41 | 42 | // enough example, lets run some tests. 43 | test('use reducer', function (t) { 44 | var state = reducer(undefined, { type: 'n/a' }) 45 | t.equal(state.num, 0, 'get initial state') 46 | state = reducer(state, {type: 'add', payload: 1}) 47 | t.equal(state.num, 1, 'add') 48 | state = reducer(state, {type: 'multiply', payload: 2}) 49 | t.equal(state.num, 2, 'multiply') 50 | state = reducer(state, {type: 'addThenMultiply', payload: 3}) 51 | t.equal(state.num, 15, 'addThenMultiply') 52 | state = reducer(state, {type: 'subtract', payload: 4}) 53 | t.equal(state.num, 15, 'Non-extant') 54 | state = reducer(state, {type: 'createSubtract', payload: 4}) 55 | state = reducer(state, {type: 'subtract', payload: 4}) 56 | t.equal(state.num, 11, 'created and used subtract') 57 | t.end() 58 | }) 59 | 60 | --------------------------------------------------------------------------------