Skip to content

Instantly share code, notes, and snippets.

@Nilzor
Last active May 5, 2016 16:06
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Nilzor/a0a29ed60bc3e4d1543b80d5503cff11 to your computer and use it in GitHub Desktop.
Save Nilzor/a0a29ed60bc3e4d1543b80d5503cff11 to your computer and use it in GitHub Desktop.
A base class for reducers. Allows generating Redux Actions for functions by introspecting and naming the action from the class and function name.
/**
* A base class for generating Redux Actions for functions
* by introspecting and naming the action after the class and function name
*/
export class AutoNamingReducer {
/** Generates and returns a Redux Action for the specified function. Function must reside in a class
* extending AutoNamingReducer
* @param func {function} A function reference
* @param params {object} An optional parameter object which will be spliced with the action object and passed
* to the action function when dispatched */
actionFor(func, params) {
let className = Object.getPrototypeOf(this).constructor.name;
let actionObj = params || {};
actionObj.type = this.createActionName(func.name);
return actionObj;
}
/** Call from reducer to invoke function from action. Returns new state if found, else same state */
tryResolveAndReduce(state, action) {
let funcList = Object.keys(Object.getPrototypeOf(this));
for (let func of funcList) {
if (this.createActionName(func) === action.type) {
console.log("AutoNamingReducer: matched " + func);
return this[func].call(this, state, action);
}
}
console.log("AutoNamingReducer: none matched " + action.type);
return state;
}
/**
* Creates an action name by concating the class name and function name
* @param funcName {string} The name of the function to create an action name for
* @return {string} The action name
*/
createActionName(funcName) {
let className = Object.getPrototypeOf(this).constructor.name;
return className + "." + funcName;
}
}
// How a reducer would be implemented with AutoNamingReducer
// -No magic strings, no switch case - just functions
class todoReducer extends AutoNamingReducer {
reduce(state = [], action = null) {
return this.tryResolveAndReduce(state, action);
}
addTodo(state, action) {
return {
id: action.id,
text: action.text,
completed: false
}
}
toggleTodo(state, action) {
if (state.id !== action.id) {
return state
}
return Object.assign({}, state, {
completed: !state.completed
})
}
}
let reducer = new todoRedcuer();
export default reducer.tryResolveAndReduce;
// Example usage
dispatch(reducer.actionFor(reducer.toggleTodo, {id: 2}));
// How a reducer would be implemented with the old pattern
const ADD_TODO = 'ADD_TODO';
const TOGGLE_TODO = 'TOGGLE_TODO';
const todo = (state, action) => {
switch (action.type) {
case ADD_TODO:
return {
id: action.id,
text: action.text,
completed: false
}
case TOGGLE_TODO:
if (state.id !== action.id) {
return state
}
return Object.assign({}, state, {
completed: !state.completed
})
default:
return state
}
}
// Example usage
dispatch({type: TOGGLE_TODO, id: 4});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment