◆ react-router-dom の Route を見ていてほしくなった
◆ JavaScript 機能での分岐じゃないので条件にマッチしない部分の仮想 DOM も作ってしまう
◆ 見やすさ的にはいいけど処理的にムダが多くなる

React の場合 条件分岐は JavaScript の処理として書きます
JSX だと {} の中で foo ? bar : baz のような感じです
これって見やすいというわけではないんですよね
特に分岐が増える場合やそれぞれの中身が大きい場合は見づらさがあります
以前 Vue のテンプレートを改良しようとしたときに考えていた if も HTML タグとしてしまうのが見やすさ的にはベストだと思うんですよね

そんな中 react-router-dom を見ていたら ふと思いました
Route って if タグですよね……
Switch と組み合わせたら if-else-if になります
Route に表示する条件を自由に書けたら使えそう……と思ったのですが Router というだけあって URL と対応していて path での比較のみみたいです

それに使えたとしてもあくまで Router なので変なことするとわかりづらくなると思います
なので専用の If と Switch コンポーネントを作ってみました

コードはプレビューの都合で Preact + htm です

<!doctype html>
<meta charset="utf-8" />

<div id="root"></div>

<script src="https://unpkg.com/htm@3.0.4/preact/standalone.umd.js"></script>
<script>
const { html, render, useState } = htmPreact

const App = () => {
const [a, setA] = useState(false)
const [b, setB] = useState(false)
const [c, setC] = useState(false)

return html`
<div>
<label>
<input type="checkbox" checked=${a} onchange=${() => setA(!a)} /> A
</label>
<label>
<input type="checkbox" checked=${b} onchange=${() => setB(!b)} /> B
</label>
<label>
<input type="checkbox" checked=${c} onchange=${() => setC(!c)} /> C
</label>
</div>
<hr />
<div>
<${If} cond=${a}>
<div>A</div>
<//>
<${If} cond=${b}>
<div>B</div>
<//>
<${If} cond=${c}>
<div>C</div>
<//>
</div>
<hr />
<div>
<${Switch}>
<${If} cond=${a}>
<div>A</div>
<//>
<${If} cond=${b}>
<div>B</div>
<//>
<${If} cond=${c}>
<div>C</div>
<//>
<//>
</div>
`
}

const Switch = (props) => props.children.find(c => c.props.cond)

const If = (props) => props.cond ? props.children : null

render(html`<${App} />`, document.getElementById("root"))
</script>

一番上にチェックボックスが 3 つ並んでいて その下には If コンポーネントを使ってチェックしたチェックボックスの ABC を表示します
ただの If なので複数チェックすると全部出ます
その更に下は Switch を使っていて 最初にマッチしたもの 1 つだけ表示します
B と C なら B ですし A と C なら A が出ます

If と Switch のコンポーネントの定義部分はとてもシンプルです

const Switch = (props) => props.children.find(c => c.props.cond)

const If = (props) => props.cond ? props.children : null

If は props.cond が true なら children を表示して false なら何も表示しません
Switch は children の中の最初に props.cond が true のものを表示します
Switch の子要素が If コンポーネントであることをチェックしてないので If 以外でも cond という props が true になるようなものであれば表示対象にできます

見やすさ的にはこっちのほうが良くなったと思います
ですが 実際にこれが使われないのも理由があって { foo ? bar : baz } であれば JavaScript の処理として分岐してマッチしたものだけが評価されます
つまり無駄が少ないです
If コンポーネントの場合は 子要素部分も含めすべてパースして createElement が実行済みです
使わない部分の仮想 DOM まで作ってしまうので無駄が大きくなります
それぞれの If の中にコンポーネントが 1 つ 2 つ程度ならともかく 中身が複雑になっている場合はパフォーマンスを気にするなら向いていません

ところで 繰り返し用に For も考えたのですが ループごとに props に渡す値を考えるとわかりやすく書けなさそうなのでやめました
ここまで来ると { items.map(item => {...}) } で良い気がしますし

<For of={items}>
{item => {
return <Component1 foo={item.bar} />
}}
</For>