Skip to content

Instantly share code, notes, and snippets.

@sergey-shpak
Last active December 16, 2018 10:26
Show Gist options
  • Save sergey-shpak/5817bf146cb970bc4e259aef71b89ef4 to your computer and use it in GitHub Desktop.
Save sergey-shpak/5817bf146cb970bc4e259aef71b89ef4 to your computer and use it in GitHub Desktop.
Hyperapp#v2 State Namespaces

It's more preferable to use lens.js or squirrel.js


Hyperapp#v2 doesn't have slices/namespaces anymore, so whenever you are working with deeply nested state you have to merge all parents each time:

const action = (state) => {
  return {
    ...state,
    deeply: {
      ...state.deeply,
      nested: {
        ...state.deeply.nested,
        property: true
      }
    }
  }
}

namespace.js - wrapps actions and emulates slices from hyperapp#v1, so now you can

// Each method under namespace will get sliced state specified by path
// Each return value will be shallow-merged into state by specified path

const actions = namespace(['deeply','nested'], {
  action(state) => {
    return { property: true }
  }
})
import { app, h } from 'hyperapp'
import namespace from 'helpers/namespace'
// Each method under namespace will get sliced state specified by path
// Each return value will be shallow-merged into state by specified path
const actions1 = namespace(['module1', 'deeply', 'nested'], {
update(state, ...args){
return { property: !state.property }
}
})
const actions2 = namespace(['module2', 'property', 'value'], {
update(state, ...args){
return ++state
}
})
document.addEventListener('DOMContentLoaded', () =>
app({
init: {
module1: {
deeply: {
nested: {
property: true
}
}
},
module2: {
property: {
value: 1
}
}
},
view: () => <div>
<input type="button" onClick={ actions1.update } value="Actions#1" />
<input type="button" onClick={ actions2.update } value="Actions#2" />
</div>,
subscriptions: console.log,
container: document.body
}
))
export default (namespaces, actions) => {
const extract = (obj, path) =>
path.reduce((obj, key) => obj[key], obj)
const merge = (target, path, value) => {
const key = path.shift()
return Object.assign({}, target, {
[key]: path.length
? merge(target[key], path, value)
: value
})
}
const wrapper = action => (state, ...args) => {
const path = [].concat(namespaces)
const value = action(extract(state, path), ...args)
return (typeof value !== 'function' && !Array.isArray(value))
? merge(state, path, value)
: value
}
return Object.keys(actions).reduce((obj, key) => {
obj[key] = (typeof actions[key] == 'function')
? wrapper(actions[key])
: actions[key]
return obj
}, {})
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment