├── .gitignore ├── CHANGES.md ├── LICENSE ├── README.md ├── lib └── index.js ├── package.json └── test └── index.js /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | -------------------------------------------------------------------------------- /CHANGES.md: -------------------------------------------------------------------------------- 1 | ## 2.0.0 2 | 3 | **Breaking change**: changed API to avoid a common source of confusion with action creators [[#1](https://github.com/insin/redux-action-utils/issues/1)] 4 | 5 | Renamed functions: 6 | 7 | * `action()` → `actionCreator()` 8 | * `optionsAction()` → `optionsActionCreator()` 9 | 10 | ## 1.0.0 11 | 12 | Initial release. 13 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2015, Jonny Buchanan 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of 4 | this software and associated documentation files (the "Software"), to deal in 5 | the Software without restriction, including without limitation the rights to 6 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 7 | the Software, and to permit persons to whom the Software is furnished to do so, 8 | subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in all 11 | copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 15 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 16 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 17 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 18 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 19 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # DEPRECATED 2 | 3 | ES6 arrow functions with implicit returns, argument destructuring and object literal enhancements make it easy to keep your action creators compact without helper functions. 4 | 5 | ## ES6 Alternative 6 | 7 | ```js 8 | import types from './action-types' 9 | 10 | export let addLesson = () => ({type: types.ADD_LESSON}) 11 | 12 | export let importLessons = (lessons) => ({type: types.IMPORT_LESSON, lessons}) 13 | 14 | export let updateLesson = ({id, update}) => ({type: types.UPDATE_LESSON, id, update}) 15 | ``` 16 | 17 | # Redux Action Utils 18 | 19 | Factory functions for reducing action creator boilerplate. 20 | 21 | ``` 22 | npm install --save redux-action-utils 23 | ``` 24 | 25 | ## Before 26 | 27 | ```js 28 | var types = require('./action-types') 29 | 30 | function addLesson() { 31 | return { 32 | type: types.ADD_LESSON 33 | } 34 | } 35 | 36 | function importLessons(lessons) { 37 | return { 38 | type: types.IMPORT_LESSONS, 39 | lessons 40 | } 41 | } 42 | 43 | function updateLesson(options) { 44 | return { 45 | type: types.SELECT_LESSON, 46 | id: options.id, 47 | update: options.update 48 | } 49 | } 50 | 51 | module.exports = {addLesson, importLessons, updateLesson} 52 | ``` 53 | 54 | ## After 55 | 56 | ```js 57 | var types = require('./action-types') 58 | var {actionCreator, optionsActionCreator} = require('redux-action-utils') 59 | 60 | module.exports = { 61 | addLesson: actionCreator(types.ADD_LESSON), 62 | importLessons: actionCreator(types.IMPORT_LESSONS, 'lessons'), 63 | updateLesson: optionsActionCreator(types.UPDATE_LESSON, 'id', 'update') 64 | } 65 | ``` 66 | 67 | ## API 68 | 69 | ### `actionCreator(type: String)` 70 | 71 | Creates an action creator which will create an action object with the given type. 72 | 73 | ```js 74 | var ac = actionCreator(types.ADD_LESSON) 75 | ac() 76 | // → {type: 'ADD_LESSON'} 77 | ``` 78 | 79 | ### `actionCreator(type: String, props: Array)` 80 | ### `actionCreator(type: String, ...props: String)` 81 | 82 | Creates an action creator which will create an action object with the given type and use the given property names to pass any positional arguments given to it. 83 | 84 | ```js 85 | var ac = actionCreator(types.IMPORT_LESSONS, 'lessons') 86 | ac(['lesson 1', 'lesson 2']) 87 | // → {type: 'IMPORT_LESSONS', lessons: ['lesson 1', 'lesson 2']} 88 | ``` 89 | 90 | ### `optionsActionCreator(type: String)` 91 | 92 | Creates an action creator which takes a single object argument and adds its properties to the action object. 93 | 94 | ### `optionsActionCreator(type: String, props: Array)` 95 | ### `optionsActionCreator(type: String, ...props: String)` 96 | 97 | Creates an action creator which takes a single object argument and adds only the specified properties from it to the action object. 98 | 99 | ```js 100 | var ac = optionsActionCreator(types.UPDATE_LESSON, 'id', 'update') 101 | ac({ 102 | id: 1 103 | update: { 104 | text: '## Lesson 1' 105 | } 106 | }) 107 | /* → 108 | { 109 | type: 'UPDATE_LESSON', 110 | id: 1, 111 | update: { 112 | text: '## Lesson 1' 113 | } 114 | } 115 | */ 116 | ``` 117 | 118 | ## MIT Licensed 119 | -------------------------------------------------------------------------------- /lib/index.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | var slice = Array.prototype.slice 4 | 5 | /** 6 | * Creates an action creator for the given action type, which optionally adds 7 | * positional arguments given to it to the action object using specified 8 | * property names. 9 | * 10 | * Property names can be specified as an Array of strings or as any number of 11 | * addiitonal String arguments; arguments passed to the action creator will 12 | * be assigned to property names in the same order the names were given in. 13 | */ 14 | function actionCreator(type) { 15 | var props = Array.isArray(arguments[1]) ? arguments[1] : slice.call(arguments, 1) 16 | return function() { 17 | if (!props.length) { 18 | return {type: type} 19 | } 20 | var args = slice.call(arguments) 21 | return props.reduce(function(action, prop, index) { 22 | return (action[prop] = args[index], action) 23 | }, {type: type}) 24 | } 25 | } 26 | 27 | /** 28 | * Creates an action creator for the given action type which also takes an 29 | * options object argument, which will either have all of its properties 30 | * or only specified properties added to the action object. 31 | * 32 | * Property names can be specified as an Array of strings or as any number of 33 | * addiitonal String arguments. 34 | */ 35 | function optionsActionCreator(type) { 36 | var props = Array.isArray(arguments[1]) ? arguments[1] : slice.call(arguments, 1) 37 | return function(options) { 38 | var copyProps = props.length === 0 ? Object.keys(options) : props 39 | return copyProps.reduce(function(action, prop) { 40 | return (action[prop] = options[prop], action) 41 | }, {type: type}) 42 | } 43 | } 44 | 45 | module.exports = { 46 | actionCreator: actionCreator, 47 | optionsActionCreator: optionsActionCreator 48 | } 49 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "redux-action-utils", 3 | "version": "2.0.0", 4 | "description": "Factory functions for reducing action creator boilerplate", 5 | "main": "./lib/index.js", 6 | "dependencies": {}, 7 | "devDependencies": { 8 | "tape": "^4.0.0" 9 | }, 10 | "scripts": { 11 | "test": "tape test/*.js" 12 | }, 13 | "repository": { 14 | "type": "git", 15 | "url": "git+https://github.com/insin/redux-action-utils.git" 16 | }, 17 | "keywords": [ 18 | "redux", 19 | "action", 20 | "creators" 21 | ], 22 | "author": "Jonny Buchanan ", 23 | "license": "MIT", 24 | "bugs": { 25 | "url": "https://github.com/insin/redux-action-utils/issues" 26 | }, 27 | "homepage": "https://github.com/insin/redux-action-utils#readme" 28 | } 29 | -------------------------------------------------------------------------------- /test/index.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | var test = require('tape') 4 | 5 | var utils = require('../lib') 6 | var actionCreator = utils.actionCreator 7 | var optionsActionCreator = utils.optionsActionCreator 8 | 9 | test('basic type-passing action creator', function(t) { 10 | t.plan(2) 11 | var ac = actionCreator('test') 12 | t.deepEqual(ac(), {type: 'test'}, 'action type is passed') 13 | t.deepEqual(ac(1, 2, 3), {type: 'test'}, 'additional arguments are ignored') 14 | }) 15 | 16 | test('action creator with positional arguments (specified as positional arguments)', function(t) { 17 | t.plan(2) 18 | var ac = actionCreator('test', 'foo', 'bar') 19 | t.deepEqual(ac(1, 2), {type: 'test', foo: 1, bar: 2}, 'action type and arguments are passed') 20 | t.deepEqual(ac(1, 2, 3), {type: 'test', foo: 1, bar: 2}, 'additional arguments are ignored') 21 | }) 22 | 23 | test('action creator with positional arguments (specified as Array)', function(t) { 24 | t.plan(2) 25 | var ac = actionCreator('test', ['foo', 'bar']) 26 | t.deepEqual(ac(1, 2), {type: 'test', foo: 1, bar: 2}, 'action type and arguments are passed') 27 | t.deepEqual(ac(1, 2, 3), {type: 'test', foo: 1, bar: 2}, 'additional arguments are ignored') 28 | }) 29 | 30 | test('action creator with unrestricted option object argument', function(t) { 31 | t.plan(2) 32 | var ac = optionsActionCreator('test') 33 | t.deepEqual(ac({foo: 1, bar: 2}), {type: 'test', foo: 1, bar: 2}, 'action type and all options are passed') 34 | t.deepEqual(ac({foo: 1, bar: 2, baz: 3}), {type: 'test', foo: 1, bar: 2, baz: 3}, 'action type and all options are passed') 35 | }) 36 | 37 | test('action creator with restricted option object argument (specified as positional arguments)', function(t) { 38 | t.plan(2) 39 | var ac = optionsActionCreator('test', 'foo', 'bar') 40 | t.deepEqual(ac({foo: 1, bar: 2}), {type: 'test', foo: 1, bar: 2}, 'action type and options are passed') 41 | t.deepEqual(ac({foo: 1, bar: 2, baz: 3}), {type: 'test', foo: 1, bar: 2}, 'additional arguments are ignored') 42 | }) 43 | 44 | test('action creator with restricted option object argument (specified as Array)', function(t) { 45 | t.plan(2) 46 | var ac = optionsActionCreator('test', ['foo', 'bar']) 47 | t.deepEqual(ac({foo: 1, bar: 2}), {type: 'test', foo: 1, bar: 2}, 'action type and options are passed') 48 | t.deepEqual(ac({foo: 1, bar: 2, baz: 3}), {type: 'test', foo: 1, bar: 2}, 'additional arguments are ignored') 49 | }) 50 | --------------------------------------------------------------------------------