Hyperappの簡単な紹介
Hyperapp は、宣言型Webアプリケーションの構築に使用される非常に小さいマイクロフレームワークです。 サイズはわずか1kBで、APIはReactに似ていますが、完璧ですよね?! Hyperappがどのように機能するかを示すために、小さなカウンターアプリを作成します。
新しいハイパープロジェクト
開始するには、新しいノードアプリケーションを作成し、hyperappをインストールします。 次に、parcelを使用してこのアプリケーションを提供します。
# New directory, here we call it `hyper` $ mkdir hyper && cd hyper # Initialise Node project $ npm init -y # Install Hyperapp $ npm i hyperapp # Create index.html and app.js $ touch index.html $ touch app.js # Install `parcel` globally $ npm i parcel -g # Serve our application in the browser $ parcel index.html
次に、hyperappコードを含むapp.jsを含む標準のindex.htmlページを作成できます。
<!DOCTYPE html> <html lang="en"> <head> <title>🎉 Hyperapp</title> </head> <body> <div id="app"></div> <script src="app.js"></script> </body> </html>
カウンターの構築
状態駆動型アプリケーションは、常に反例から始まります。 これにより、アプリケーション内でのデータの流れに慣れることができます。 いくつかのstateを定義することから始めましょう:
app.js
const state = {
count: 0
}
次に、そのstateに基づいてviewを定義できます。 これは、標準のテンプレート構文を使用して表示できます。
app.js
// ...
const view = state => (
<div>
<h1>{state.count}</h1>
</div>
);
最後に、これをDOM内の特定の要素にアタッチできます。 appのidを使用して、これをdivに追加することを選択しました。
app.js
// ...
const el = document.getElementById('app');
const main = app(state, {}, view, el);
シンプルなアプリは次のようになります。
stateは不変であり、直接更新する必要がないため、actionsを追加して、stateを次のように操作できます。
app.js
// ...
const actions = {
increment: () => state => ({ count: (state.count += 1) }),
decrement: () => state => ({ count: (state.count -= 1) })
};
これは、mainおよびviewの内部に配線して、actionsにアクセスできるようにすることができます。
app.js
// ...
const view = (state, actions) => (
<div>
<h1>{state.count}</h1>
<button onclick={() => actions.increment()}>Increment</button>
<button onclick={() => actions.decrement()}>Decrement</button>
</div>
);
const main = app(state, actions, view, el);
ここで、[インクリメント]または[デクリメント]を選択すると、合計カウントが増減します。
これを特定の数だけ上下させたい場合はどうなりますか? この機能を追加しましょう。
まず、stateオブジェクトに新しいアイテムを追加できます。 これをdiffと呼ぶことにしました。これは、加算と減算の違いを表すためです。
const state = {
count: 1,
diff: 1
};
次に、actionsを更新して、これに基づいてインクリメントまたはデクリメントできます。
const actions = {
updateCount: diff => state => ({ diff: diff }),
increment: diff => state => ({ count: (state.count += Number(diff)) }),
decrement: diff => state => ({ count: (state.count -= Number(diff)) })
};
そして最後に、viewを更新できます。
const view = (state, actions) => (
<div>
<input value={state.diff} oninput={e => actions.updateCount(e.target.value)} />
<h1>{state.count}</h1>
<button onclick={() => actions.increment(state.diff)}>Increment</button>
<button onclick={() => actions.decrement(state.diff)}>Decrement</button>
</div>
);
これで、入力データを利用して状態を更新できるようになりました。
コンポーネント
Hyperappプロジェクトからコンポーネントを作成する方法を見てみましょう。 Counterコンポーネントを作成し、これをページとルートの中に埋め込む方法を見ていきます。
components/Count.jsに新しいファイルを作成し、propsからcountを取り込むカウンターを追加します。
Count.js
import { h } from 'hyperapp';
const Count = ({ count }) => <h1>{count}</h1>;
export default Count;
次に、app.jsの内部でimportを実行できます。
app.js
import Count from './components/Count'; // ...
次に、countを小道具としてview内のCountに渡すことができます。
app.js
// ...
const view = () => (state, actions) => (
<div>
<Count count={state.count} />
<button onclick={actions.increment}>Increment</button>
<button onclick={actions.decrement}>Decrement</button>
</div>
);
また、stateとactionsをcountの単純なincrementとdecrementに更新しました。
const state = {
count: 0
};
const actions = {
increment: () => ({ count: (state.count += 1) }),
decrement: () => ({ count: (state.count -= 1) })
};
ルーティング
Hyperapp内のルーティングを利用することもできます。 次のようにルーターパッケージ(@hyperapp/router)をインストールしましょう。
$ npm i @hyperapp/router
次に、app.js内のルーティングコンポーネントをimportできます。
app.js
import { Link, Route, location } from '@hyperapp/router';
これで、HomeとBlogの2つの異なるページを作成できます。
app.js
// ...
const Home = () => (state, actions) => (
<div>
<Count count={state.count} />
<button onclick={actions.increment}>Increment</button>
<button onclick={actions.decrement}>Decrement</button>
</div>
);
const Blog = () => <h1>Blog!</h1>;
Homeページには以前の反例が含まれており、Blogページは単なるテキストです。 これらをRouteとLinkとして、viewの内部に割り当てましょう。
app.js
// ...
const view = state => (
<div>
<ul>
<li>
<Link to="/">Home</Link>
</li>
<li>
<Link to="/blog">Blog</Link>
</li>
</ul>
<Route path="/" render={Home} />
<Route path="/blog" render={Blog} />
</div>
);
次に、History APIに基づいているため、ルーターにlocationへのアクセスを許可する必要があります。 stateとactionsに以下を追加します。
app.js
const state = {
location: location.state,
count: 0
};
const actions = {
location: location.actions,
increment: () => state => ({ count: (state.count += 1) }),
decrement: diff => state => ({ count: (state.count -= 1) })
};
最後に、location自体をサブスクライブする必要があります。
app.js
// ... const unsubscribe = location.subscribe(main.location);
これで、アプリケーション内のさまざまなページから選択できるようになりました。
ルーティング例の完全なコードは次のとおりです。
app.js
import { h, app } from 'hyperapp';
import { Link, location } from '@hyperapp/router';
import Count from './components/Count';
const state = {
location: location.state,
count: 0
};
const actions = {
location: location.actions,
increment: () => state => ({ count: (state.count += 1) }),
decrement: diff => state => ({ count: (state.count -= 1) })
};
const Home = () => (state, actions) => (
<div>
<Count count={state.count} />
<button onclick={actions.increment}>Increment</button>
<button onclick={actions.decrement}>Decrement</button>
</div>
);
const Blog = () => <h1>Blog!</h1>;
const view = state => (
<div>
<ul>
<li>
<Link to="/">Home</Link>
</li>
<li>
<Link to="/blog">Blog</Link>
</li>
</ul>
<Route path="/" render={Home} />
<Route path="/blog" render={Blog} />
</div>
);
const main = app(state, actions, view, document.body);
const unsubscribe = location.subscribe(main.location);
結論
これで、あなたはレースに出かける必要があります! 🏇また、 Hyperapp2.0にも注目してください。まもなくリリースされる予定です。