Virtual DOM を使ったフロントエンドライブラリである deku のバージョン1.0がリリースされたようなので使ってみます。

インストール

Browserify と Babel を使うのでインストールします。 JSX のためのプラグインもいれて起きます。

deku だけでなく virtual-element も必要です。

$ npm install -g browserify
$ npm install -D babelify babel-preset-es2015 babel-plugin-transform-react-jsx
$ npm install -S virtual-element deku

Hello, World!

まずは Hello, World! から

// a.js

import { render, tree } from 'deku';
import element from 'virtual-element';

let Greeting = {
    render() {
        return <div>Hello, {props.children}!</div>;
    }
};

render(tree(<Greeting>deku</Greeting>), document.querySelector('div'));

これをビルドするための .babelrc ファイルが以下です。

{
    "plugins": [
        ["transform-react-jsx", { "pragma": "element" }]
    ],
    "presets": [
        "es2015"
    ]
}

browserify -t babelify -o bundle.js a.js コマンドで bundle.js をビルドできます。

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
</head>
<body>
    <div></div>
    <script src="bundle.js"></script>
</body>
</html>

この HTML を開くと Hello, deku! と表示されます。

タイマー処理

setTimeout を仕込んで表示する内容を変更してみます。

import element from 'virtual-element';
import { render, tree } from 'deku';

const timeoutId = Symbol();

let Greeting = {
    initialState(props) {
        return {
            content: props.children
        };
    },
    render({ state }) {
        return <div>Hello, {state.content}!</div>;
    },
    afterMount(component, element, setState) {
        component[timeoutId] = setTimeout(() => {
            setState({ content: 'virtual DOM' });
        }, 1000);
    },
    beforeUnmount(component) {
        clearTimeout(component[timeoutId]);
    }
};

render(tree(<Greeting>deku</Greeting>), document.querySelector('div'));

最初に initialState が呼び出されます。そこで作った state を使ってレンダリングします。

afterMount が実際に DOM が作られたあとに呼び出されるのでそこで setTimeout を仕込みます。 DOM が消される時に beforeUnmount が呼び出されるので、無駄なタイマーが残らないように clearTimeout を忘れないようにしておきます。

これをビルドして1秒待つと Hello, virtual DOM! と表示されます。

クリックイベント

クリックに反応するコードも書いてみます。

import element from 'virtual-element';
import { render, tree } from 'deku';

let Greeting = {
    initialState(props) {
        return {
            content: props.children
        };
    },
    render({ state }) {
        const onClick = (event, component, setState) => {
            setState({ content: 'mouse' });
        };
        return <div onClick={onClick}>Hello, {state.content}!</div>;
    }
};

render(tree(<Greeting>deku</Greeting>), document.querySelector('div'));

クリックイベントは onClick プロパティに関数を入れるとハンドルできるようです。

これを表示してテキストをクリックすると Hello, mouse! という表示に変わります。

さいごに

deku で Virtual DOM を試してみました。

React と違い render メソッドのあるオブジェクトを作るだけでいいので軽く使えそうです。