Skip to content

Instantly share code, notes, and snippets.

@sergeysova
Created October 23, 2017 15:37
Show Gist options
  • Select an option

  • Save sergeysova/dde2522bc52b22b7a1cb487a6da44c9d to your computer and use it in GitHub Desktop.

Select an option

Save sergeysova/dde2522bc52b22b7a1cb487a6da44c9d to your computer and use it in GitHub Desktop.
const actName = (ns, nm) => ns ? `${ns}/${nm}` : nm
function createActionTypes(namespace, namelist) {
if (Array.isArray(namespace)) {
namelist = namespace
namespace = false
}
return namelist.reduce((map, name) =>
Object.assign(map, {
[name]: actName(namespace, name)
}),
{}
)
}
const pass = (obj) => obj
const empty = () => null
function createActions(namespace, actionsMap) {
return Object.keys(actionsMap).reduce((map, name) => {
const actionFn = actionsMap[name]
const type = actName(namespace, name)
const actionCreator = (...args) => ({
type,
payload: actionFn(...args)
})
actionCreator.type = type
return Object.assign(map, { [name]: actionCreator })
}, {})
}
class Action {
constructor() {
this.effects = []
}
map(fn) {
this.effects.push({ type: 'map', fn })
return this
}
update(fn) {
this.effects.push({ type: 'update', fn })
return this
}
build() {
return (state, action) => {
let value = action.payload
for (const effect of this.effects) {
switch (effect.type) {
case 'map':
value = effect.fn(value)
break;
case 'update': {
return effect.fn(value, state)
}
}
}
return value
}
}
}
function action() {
return new Action
}
function reducer(initial) {
const actionsMap = {}
function realReducer(state, action) {
if (actionsMap[action.type]) {
return actionsMap[action.type](state, action)
}
return initial
}
realReducer.of = (actionType, action) => {
actionsMap[actionType.type || actionType] = action.build()
return realReducer
}
return realReducer
}
// ===== USAGE ===== //
const Types = createActionTypes('foo', ['baz', 'baf'])
console.log(Types)
const Actions = createActions('profile', {
reset: empty,
setName: (name) => ({ name }),
update: pass,
})
console.log(Actions.reset())
console.log(Actions.setName('Sova'))
console.log(Actions.update({ foo: 'bar' }))
const red = reducer({ first: '', last: '' })
.of(
Actions.setName,
action()
.map(({ name }) => name.split(' '))
.update(([first, last], state) => ({ ...state, first, last }))
)
console.log(red({}, Actions.setName('Sergey Sova')))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment