uchcode
6/9/2018 - 1:27 PM

Classを使用してHyperappを書いてみた ref: https://qiita.com/tom-u/items/5566fecf51fc30fff007

Classを使用してHyperappを書いてみた ref: https://qiita.com/tom-u/items/5566fecf51fc30fff007

<!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="text/javascript" src="https://unpkg.com/hyperapp"></script>
    <script>

      const { app, h } = hyperapp

      class Hyperclass {
        constructor() {
          this.state = {}
          this.actions = {}
          this.view = (state, actions) => h("h1", {}, "Hyperclass")
        }
        appendTo(container) {
          return app(this.state, this.actions, this.view, container)
        }
      }

      class Counter extends Hyperclass {
        constructor(className='counter') {
          super()
          this.state = {
            count: 0,
          }
          this.actions = {
            up  : by => s => ({ count: s.count+by }),
            down: by => s => ({ count: s.count-by }),
          }
          this.view = (s,a) => h("div", {class:className}, [
            h("h1", {}, s.count),
            h("button", {onclick:()=>a.up(1)}, `+1`),
            h("button", {onclick:()=>a.down(1)}, `-1`),
          ])
        }
      }

      class TwinCounter extends Hyperclass {
        constructor(className='twinCounter') {
          super()
          const c1 = new Counter()
          const c2 = new Counter()
          const twinActionButton = text => (s,a) =>
            h("button", {onclick:()=>a.twinAction()}, text)
          this.state = {
            counter1: c1.state,
            counter2: c2.state,
          }
          this.actions = {
            counter1: c1.actions,
            counter2: c2.actions,
            twinAction: () => (s,a) => {
              a.counter1.up(1)
              a.counter2.down(1)
            },
          }
          this.view = (s,a) => h("div", {class:className}, [
            twinActionButton("twin action"),
            c1.view(s.counter1,a.counter1),
            c2.view(s.counter2,a.counter2),
          ])
        }
      }

      const component = new TwinCounter()

      const widget = component.appendTo(document.body)

      for(let i=0; i<10000; i++) setTimeout(widget.twinAction, i)

    </script>
  </body>
</html>
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)
<!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>