11
6

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

hyperappを読んでReactをわかった気持ちになれるのか

Last updated at Posted at 2017-03-17
1 / 13

hyperapp ?


サンプルコード(カウンター)

index.js
app({
  model: 0,
  actions: {
    add: model => model + 1,
    sub: model => model - 1
  },
  view: (model, actions) =>
    <div>
      <button onClick={actions.add}>
        +
      </button>
      <h1>{model}</h1>
      <button onClick={actions.sub}>
        -
      </button>
    </div>
})
index.html
<!doctype html>
<html lang="en">
<head>
  <title>Hello HyperApp</title>
</head>

<body>
<script src="bundle.js"></script>
</body>
</html>

hyperappが持っている機能

  • 宣言的にUIを記述
  • VirualDOMみたいに差分だけ更新する
  • Reduxみたいな状態管理
  • plugin機構
  • Router(pluginとして提供)
  • など
  • Wiki#Reference

いやー300行とはいえJSかぁ…


機能を最小限にしたやつを用意しました :tada:


tr;dr

  • JSXからVirtualNodeを作る
  • VirtualNodeからDOMを作成する
  • actionで状態を変更する
  • oldNode, nodeを比べて変わったとこだけDOMをいじる

JSXからVirtualNodeを作る

babelとhyperappのh関数がよしなにJSXをVirtualNodeに変換する様子

$ cd ./examples/helloworld
$ npm i
$ babel-node
> const { h } = require('hyperapp')
undefined
> <a href="/foo">hello</a>
{ tag: 'a', data: { href: '/foo' }, children: [ 'hello' ] }
> <ul><li>foo</li><li>bar</li></ul>
{ tag: 'ul',
  data: {},
  children:
   [ { tag: 'li', data: {}, children: [Object] },
     { tag: 'li', data: {}, children: [Object] } ] }

VirtualNodeからDOMを作成する

root = document.body.appendChild(document.createElement("div"))
root.appendChild(createElementFrom(node))

function createElementFrom(node) {
  var element

  if (typeof node === "string") {
    element = document.createTextNode(node)

  } else {
    element = document.createElement(node.tag)

    for (var name in node.data) {
      setElementData(element, name, node.data[name])
    }

    for (var i = 0; i < node.children.length; i++) {
      element.appendChild(createElementFrom(node.children[i]))
    }
  }

  return element
}

actionで状態を変更する

var result = action(model, data, actions)

model = merge(model, result)
render(model, view)

oldNode, nodeを比べて変わったとこだけDOMをいじる

if (shouldUpdate(node, oldNode)) {
  if (typeof node === "string") {
    element.textContent = node
  } else {
    parent.replaceChild(createElementFrom(node), element)
  }

} else if (node.tag) {
  updateElementData(element, node.data, oldNode.data)

  var len = node.children.length, oldLen = oldNode.children.length

  for (var i = 0; i < len || i < oldLen; i++) {
    // childrenにも再帰的にpatchしていく
    patch(element, oldNode.children[i], node.children[i], i)
  }
}

  • 意外?と素朴な実装だと思った
  • ReactもReactElementだかで同じことやってる気がする
  • Reactをわかった気持ちになった

おわり

11
6
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
11
6

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?