Help us understand the problem. What is going on with this article?

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

More than 1 year has passed since last update.

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

by maaz118
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をわかった気持ちになった

おわり

Why do not you register as a user and use Qiita more conveniently?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away