Skip to content

Instantly share code, notes, and snippets.

@brandonpapworth
Created April 4, 2018 11:13
Show Gist options
  • Save brandonpapworth/b8b268707f6d7e27bc8d381d21db4e86 to your computer and use it in GitHub Desktop.
Save brandonpapworth/b8b268707f6d7e27bc8d381d21db4e86 to your computer and use it in GitHub Desktop.
Using class-based action types instead of strings in Reduxsauce
'use strict';
const __ACTION_TYPE_NAME__ = Symbol('ActionType[__ACTION_TYPE_NAME__]');
const actionTypeSingletonStore = new Map();
export class ActionType {
constructor(actionTypeName, ignoreActionTypeSingletonStore = false) {
if (ignoreActionTypeSingletonStore === false) {
let actionTypeInstance = actionTypeSingletonStore.get(actionTypeName);
if (actionTypeInstance === undefined) {
actionTypeSingletonStore.set(actionTypeName, this);
} else {
return this;
}
}
this[__ACTION_TYPE_NAME__] = actionTypeName;
}
toString() {
return this[__ACTION_TYPE_NAME__];
}
toJSON() {
return this[__ACTION_TYPE_NAME__];
}
}
'use strict';
/**
* This replaces the `createActions` library function of reduxsauce to allow for
* class-based types to be used.
* https://github.com/infinitered/reduxsauce/blob/master/lib/createActions.js
* [specific time referenced] https://github.com/infinitered/reduxsauce/blob/7735e5129183fe8a76b233405ecbc2fdb5ddd76b/lib/createActions.js
*/
import { is, isNil, isEmpty, join, keys, map, mapObjIndexed, merge, pick, pipe, replace, toUpper, zipObj } from 'ramda';
import { ActionType } from './action-type.class';
import { createTypes } from './create-types.class-based';
const DEFAULT_OPTIONS = {
prefix: ''
};
const RX_CAPS = /(?!^)([A-Z])/g;
const camelToScreamingSnake = pipe(
replace(RX_CAPS, '_$1'),
toUpper
);
function convertToTypes(config, options) {
const opts = merge(DEFAULT_OPTIONS, options);
return pipe(
keys,
map(camelToScreamingSnake),
join(' '),
types => createTypes(types, opts)
)(config);
}
function createActionCreatorWithOnlyType(type) {
return function createAction() { return { type }; };
}
function createActionCreatorWithArrayOfPropNames(type, propNames) {
return function createAction(...values) {
var extraProps = zipObj(propNames, values);
return { type, ...extraProps };
};
}
function createActionCreatorWithDefaultProps(type, defaultProps) {
const defaultPropKeys = Object.keys(defaultProps);
return function createAction(valueObject) {
const providedProps = pick(defaultPropKeys, valueObject);
return { type, ...defaultProps, ...providedProps };
};
}
function createActionCreator(name, extraPropNames, options) {
const { prefix } = merge(DEFAULT_OPTIONS, options);
const type = new ActionType(`${prefix}${camelToScreamingSnake(name)}`);
const noKeys = isNil(extraPropNames) || isEmpty(extraPropNames);
let actionCreator = undefined;
if (noKeys) {
actionCreator = createActionCreatorWithOnlyType(type);
} else if (is(Array, extraPropNames)) {
actionCreator = createActionCreatorWithArrayOfPropNames(type, extraPropNames);
} else if (is(Object, extraPropNames)) {
actionCreator = createActionCreatorWithDefaultProps(type, extraPropNames);
} else {
throw new Error('action props must be a null/array/object/function');
}
return actionCreator;
}
function convertToCreators(config, options) {
return mapObjIndexed((num, key, value) => {
if (typeof value[key] === 'function') {
return value[key];
} else {
return createActionCreator(key, value[key], options);
}
})(config);
}
export default function createActions(config, options) {
if (isNil(config)) {
throw new Error('an object is required to setup types and creators')
}
if (isEmpty(config)) {
throw new Error('empty objects are not supported')
}
return {
Types: convertToTypes(config, options),
Creators: convertToCreators(config, options)
};
}
'use strict';
import { createTypes as reduxsauceCreateTypes } from 'reduxsauce';
import { ActionType } from './action-type.class';
export createTypes(...args) {
return Object
.entries(reduxsauceCreateTypes(...args))
.reduce((typesObject, [typeName, prefixedTypeName]) => {
typesObject[typeName] = new ActionType(prefixedTypeName);
return typesObject;
}, {});
;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment