--- title: hyperappを読んでReactをわかった気持ちになれるのか tags: JavaScript React hyperapp author: maaz118 slide: true --- # hyperapp ? - https://github.com/hyperapp/hyperapp - **300行**で書かれたReact/ReduxライクなFW - `dependencies: {}` ---- サンプルコード(カウンター) ```js:index.js app({ model: 0, actions: { add: model => model + 1, sub: model => model - 1 }, view: (model, actions) =>

{model}

}) ``` ```html:index.html Hello HyperApp ``` ---- # hyperappが持っている機能 - 宣言的にUIを記述 - VirualDOMみたいに差分だけ更新する - Reduxみたいな状態管理 - plugin機構 - Router(pluginとして提供) - など - [Wiki#Reference](https://github.com/hyperapp/hyperapp/wiki/Reference) ---- # いやー300行とはいえJSかぁ… ---- # 機能を最小限にしたやつを用意しました :tada: - https://github.com/adwd/hyperapp - Router, pluginなどを消して最小限に - それでも200行になった程度ですが :rolling_eyes: ---- # tr;dr - JSXからVirtualNodeを作る - VirtualNodeからDOMを作成する - actionで状態を変更する - oldNode, nodeを比べて変わったとこだけDOMをいじる --- # JSXからVirtualNodeを作る babelとhyperappのh関数がよしなにJSXをVirtualNodeに変換する様子 ```sh $ cd ./examples/helloworld $ npm i $ babel-node > const { h } = require('hyperapp') undefined > hello { tag: 'a', data: { href: '/foo' }, children: [ 'hello' ] } > { tag: 'ul', data: {}, children: [ { tag: 'li', data: {}, children: [Object] }, { tag: 'li', data: {}, children: [Object] } ] } ``` --- # VirtualNodeからDOMを作成する ```js 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で状態を変更する ```js var result = action(model, data, actions) model = merge(model, result) render(model, view) ``` ---- # oldNode, nodeを比べて変わったとこだけDOMをいじる ```js 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をわかった気持ちになった ---- # おわり