バニラ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ツリーの作成
TodoInput と TodoList クラスを使って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件のコメント
Hacker Newsのコメント
プロジェクトに関心を持ってくれてありがとう
実際のDOMノードを返すと、JSXの大きな利点が失われる
JSXの起源はFacebookのXHPに由来する
最後の例がFirefoxでは動かない
Vanilla TSXと非常によく似ている
ActionScript 3を思い出させる
例では、時間の経過とともに変化しうるpropsを持つコンポーネントが示されていない
私も実際のDOMノードを生成するjsxテンプレート式ベースのUIライブラリを作った
JSXの魅力が理解できない
Imbaを勧める