state
、actions
、view
を Class で書いておけば再利用も楽になりそうと思ってやってみた。多分いい感じ。
Hyperapp用のクラスをHyperclassって呼びたい。
hyperclass.html
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
</head>
<body>
<script type="module">
import { h, app as mount} from 'https://unpkg.com/hyperapp?module'
class Hyperclass {
constructor() {
this.state = {}
this.actions = {}
this.view = (state, actions) => h("h1", {}, "Hyperclass")
}
appendTo(container) {
return mount(this.state, this.actions, this.view, container)
}
assign(namespace, component) {
this[namespace] = { view: component.view }
this.state[namespace] = component.state
this.actions[namespace] = component.actions
}
}
class Counter {
constructor(classname='counter') {
this.state = {
count: 0,
}
this.actions = {
up : (by) => (state, actions) => ({count: state.count+by}),
down: (by) => (state, actions) => ({count: state.count-by}),
}
this.view = (state, actions) => h("div", {class:classname}, [
h("h1", {}, state.count),
h("button", {onclick:()=>actions.up(1)}, '+1'),
h("button", {onclick:()=>actions.down(1)}, '-1'),
])
}
}
class TwinCounter extends Hyperclass {
constructor(cls='twinCounter') {
super()
this.assign('c1', new Counter())
this.assign('c2', new Counter())
Object.assign(this.actions, {
twin: _ => (s,a) => {
a.c1.up(1)
a.c2.down(1)
},
})
const tree = c => h("div",{class:cls},c)
const button = t => (s,a) => h("button",{onclick:a.twin},t)
const view1 = _ => (s,a) => this.c1.view(s.c1,a.c1)
const view2 = _ => (s,a) => this.c2.view(s.c2,a.c2)
this.view = (s,a) => tree([
button("twin action"),
view1(),
view2(),
])
}
}
const component = new TwinCounter()
const widget = component.appendTo(document.body)
for(let msec=0; msec<10000; msec++) setTimeout(widget.twin, msec)
</script>
</body>
</html>
追記:次期Hyperappでこんな風に書けるといいな。自分でもチャレンジしてみたい。
hyperclass-example.js
import Hyperclass from './hyperclass.js'
class Counter extends Hyperclass {
constructor(classname='counter') {
this.classname = classname
this.count = 0
}
up(by) {
//this.count += by
return self => ({count: self.count + by})
}
down(by) {
//this.count -= by
return self => ({count: self.count - by})
}
view(self) {
return h("div", {class:self.classname}, [
h("h1", {}, self.count),
h("button", {onclick:()=>self.up(1)}, '+1'),
h("button", {onclick:()=>self.down(1)}, '-1'),
])
}
}
class TwinCounter extends Hyperclass {
constructor(classname='twincounter') {
this.classname = classname
this.counter1 = new Counter()
this.counter2 = new Counter()
}
twin() {
return self => {
self.counter1.up(1)
self.counter2.down(1)
}
}
view(self) {
return h("div", {class:self.classname}, [
h("button", {onclick:()=>self.twin()}, "twin action"),
self.counter1.view(self.counter1),
self.counter1.view(self.counter2),
])
}
}
new TwinCounter().appendTo(document.body)