loading...

elm-tsでReactの代わりにPreactを使う

e_ntyo profile image e_ntyo ・1 min read

TL; DR

  • gcanti/elm-ts というライブラリがあり、fp-tsElm Architectureを実装している
  • elm-tsはvirtual-domの代わりにReactを使っているがPluggableである
    • > React instead of virtual-dom (pluggable)
    • しかし、具体的にどのように他のVirtual DOMの実装を使えばよいか具体的な記述はない
    • この記事ではPreactを使う場合の具体的なやり方を紹介する。おそらく同じやり方で他のVirtual DOMの実装(snabbdom-modulesなど)も使うことが出来るはず

やり方

一言で言えば、elm-ts/lib/ReactHtml インターフェースの代わりにPreact Compatibleな Html インターフェースを自前で定義して使えばok。

/**
 * `Dom` is a `ReactElement`.
 * @category model
 * @since 0.5.0
 */
export interface Dom extends ReactElement<any> {
}
/**
 * `Html` has `Dom` type constrained to the specialized version for `React`.
 * @category model
 * @since 0.5.0
 */
export interface Html<Msg> extends html.Html<Dom, Msg> {
}

elm-ts/lib/ReactHtml インターフェースの定義はこんな感じなので、Dom(=ReactElement<any>)をPreact相当のものに差し替えればよさそう。

// Instead of Html, use PreactHtml
export type PreactHtml<Msg> = Html<h.JSX.Element, Msg>;

よしなにview functionの定義で PreactHtml を使う。

export function view(model: Model): PreactHtml<Msg> {
  return <div>...</div>
}

あとは programrun するだけだが、React.program を使うことはできないので elm-ts/lib/Htmlprogram を次のようにして使う。

import { programWithDebuggerWithFlags } from "elm-ts/lib/Debug/Html";

import { Flags, Model, Msg, flags, init, update, view } from "./App";
import { programWithFlags, run } from "elm-ts/lib/Html";
import { VNode, h, render } from "preact";

// React.programはもういないんだ
const program = process.env.NODE_ENV === "production" ? programWithFlags : programWithDebuggerWithFlags;

// もうあの時間は終わって、君も人生と向き合う時なんだ
// programのGenericsの4つ目にpreactの VNode を使っているところに注意
const main = program<Flags, Model, Msg, VNode>(init, update, view);

const app = document.getElementById("app");
if (app === null) {
  throw new Error("id=appな要素がない");
}

run(main(flags), dom => render(dom, app));

おわり。

おことわり

  • elm-tsはできて間もないライブラリなので仕様がすぐ変わり、このやり方では動かなくなるかも
    • 公式のREADMEにPRを出さずにBlog Postにした理由はこれ

Posted on by:

Discussion

markdown guide