3 ポイント 投稿者 GN⁺ 2024-08-17 | 1件のコメント | WhatsAppで共有

バニラJSXの事例

JSXがDOM要素を返すなら?

  • ClickMe 関数はボタンを生成し、クリック回数を表示する機能を持つ
  • ボタンをクリックするたびにテキストが更新される
export default function ClickMe() {
  let i = 0;
  const el = <button>Click me</button> as HTMLButtonElement;
  el.onclick = (e) => {
    el.textContent = `Clicked ${++i} times`;
  };
  return el;
}

再利用性

  • ClickMe コンポーネントを複数回使用して、それぞれ異なる状態を維持できる
import ClickMe from "./sample1.js";
export default () => <>
  <p><ClickMe /></p>
  <p><ClickMe /></p>
  <p><ClickMe /></p>
</>;

インタラクティブなDOMツリーの作成

  • TodoInputTodoList クラスを使ってToDoリストを管理できる
  • 項目を追加し、クリックして削除できる
function TodoInput(attrs: { add: (v: string) => void }) {
  const input = <input /> as HTMLInputElement;
  input.placeholder = 'Add todo item...';
  input.onkeydown = (e) => {
    if (e.key === 'Enter') {
      attrs.add(input.value);
      input.value = '';
    }
  };
  return input;
}

class TodoList {
  ul = <ul class='todolist' /> as HTMLUListElement;
  add(v: string) {
    const item = <li>{v}</li> as HTMLLIElement;
    item.onclick = () => item.remove();
    this.ul.append(item);
  }
}

export default () => {
  const list = new TodoList();
  list.add('foo');
  list.add('bar');
  return <>
    <TodoInput add={(v) => list.add(v)} />
    {list.ul}
  </>;
};

大量データの処理

  • FindNames 関数は大量のデータを処理・フィルタリングして結果を表示する
  • 入力値に応じて一致する項目をリアルタイムで更新する
import { data } from "../fetch-dataset.js";
export default function FindNames() {
  const status = <p style='margin:1em 0' /> as HTMLParagraphElement;
  const results = <ul /> as HTMLUListElement;
  const input = <input value='eri(c|k)a?' autocomplete='new-password' oninput={updateMatches} /> as HTMLInputElement;
  updateMatches();

  function updateMatches() {
    const matched = (data.entries().filter(([k]) => k.match(input.value)).toArray());
    const matches = (Iterator.from(matched).map(match => <Item regex={input.value} match={match} />).take(30));
    results.replaceChildren(...matches);
    status.textContent = `${matched.length} / ${data.size}`;
  }

  return <div class='sample4'>
    {input}
    {status}
    {results}
  </div>;
}

function Item(attrs: { match: [string, number], regex: string }) {
  const [name, count] = attrs.match;
  const total = <small style='color:#fff3'>({count})</small>;
  return <li>
    <span innerHTML={highlight(name, attrs.regex)} /> {total}
  </li>;
}

function highlight(str: string, regex: string) {
  if (!regex) return str;
  const r = new RegExp(`(${regex})`, 'gi');
  return str.replace(r, '<span class="match">$1</span>');
}

imlibの紹介

  • imlib は immaculatalibrary.com のために開発されたライブラリである
  • minigamemaker.com と、いま読んでいるウェブサイトの構築に使われている
  • 既存の状態管理では十分でなかったために開発され、アプリを作るうえで最も好まれる方法である

GN⁺のまとめ

  • この記事は、JSXを使ってDOM要素を直接生成し、相互作用させる方法を説明している
  • 従来の仮想DOMを使わなくても、効率的に大量データを処理できる方法を示している
  • imlib ライブラリは、シンプルで直感的な方法でアプリを開発できるようにする
  • 類似の機能を持つ他のプロジェクトには React、Vue.js などがある

1件のコメント

 
GN⁺ 2024-08-17
Hacker Newsのコメント
  • プロジェクトに関心を持ってくれてありがとう

    • 過去10年間のSSGsの状況に不満を感じ、このプロジェクトを始めた
    • 主に静的ウェブサイトを作っており、シンプルで直感的なものを求めていた
    • JSXが適しているように見えたが、ReactのようなJSXフレームワークの複雑さにうんざりしていた
    • JSXを文字列としてレンダリングするSSGを作り、それをブラウザでDOM要素としてレンダリングするよう拡張した
    • 一部のレイアウトでは共有コンポーネントとしてうまく機能する
    • SEOにもよく機能する
    • IDEのサポートは完全ではない
  • 実際のDOMノードを返すと、JSXの大きな利点が失われる

    • DOMの記述を返す必要があり、そうすることで新しい状態でテンプレートを再評価し、効率的に更新できる
    • 例では命令型のDOM APIを使って更新している
    • VDOMの主な利点は、テンプレート内で項目を繰り返せること
    • VDOMの問題は、diffingが遅いこと
  • JSXの起源はFacebookのXHPに由来する

    • XHPはE4Xに着想を得ている
  • 最後の例がFirefoxでは動かない

    • Edgeでは動くが、Firefoxではエラーが発生する
  • Vanilla TSXと非常によく似ている

    • Vanilla TSXで書かれたアプリの例がある
  • ActionScript 3を思い出させる

    • XMLが言語の中核で、楽しかったがES4にはならなかった
    • TypeScriptとJSXで同程度の水準に到達するまで10年以上かかった
  • 例では、時間の経過とともに変化しうるpropsを持つコンポーネントが示されていない

    • より複雑なアプリへ拡張するのは難しそうだ
  • 私も実際のDOMノードを生成するjsxテンプレート式ベースのUIライブラリを作った

    • モデルオブジェクトをプロパティにバインドし、命令型イベントハンドラのボイラープレートをなくした
    • 良いアイデアだと思う
  • JSXの魅力が理解できない

    • ループや変数挿入などを自動で提供する別の方法のほうが簡単だ
  • Imbaを勧める

    • JS開発者はFAANGマーケティングに簡単に流されるので、人気が出ないのだと思う