Part 1 · React の世界観
JSX と TSX
HTML に見えるが HTML ではない。その正体
React のコードを開くと、JavaScript の中に いきなり HTML のようなものが書いてあって面食らいます。
これは JSX と呼ばれる書き方で、HTML ではありません。 見た目が似ているだけで、正体は JavaScript です。
そこを取り違えると、「なぜ class ではなく className なのか」 「なぜ波括弧が必要なのか」がずっと腑に落ちないままになります。
JSX は JavaScript に変換される
JSX はそのままブラウザに届くわけではありません。 ビルドのときに、ふつうの JavaScript の関数呼び出しに書き換えられます。
// 書いているもの
<p className="text">こんにちは</p>
// 変換されたもの(イメージ)
jsx("p", { className: "text", children: "こんにちは" })つまり JSX は「関数呼び出しの見た目を HTML 風にしたもの」です。 タグに見えているものは、実際には関数の引数です。
jsx-expression.tsx
const name = "さとう";
const price = 1200;
const tags = ["React", "TypeScript"];
export function JsxExpression() {
return (
<ul className="flex flex-col gap-2.5">
{/* 変数をそのまま置ける */}
<li className="rounded-md border p-2.5">{name} さん</li>
{/* 計算もできる。式なら何でもよい */}
<li className="rounded-md border p-2.5">{price * 1.1} 円(税込)</li>
{/* メソッドの呼び出しも式 */}
<li className="rounded-md border p-2.5">{name.length} 文字</li>
{/* 条件による出し分けも、三項演算子なら式として書ける */}
<li className="rounded-md border p-2.5">
{tags.length > 0 ? tags.join(" / ") : "タグなし"}
</li>
</ul>
);
}波括弧で JavaScript に戻る
JSX の中で { } を書くと、そこだけ JavaScript に戻ります。 中には式なら何でも書けます。
変数・計算・メソッド呼び出し・条件
- さとう さん
- 1320 円(税込)
- 3 文字
- React / TypeScript
ポイントは「式」しか書けないことです。 値になるものは書けますが、値にならないものは書けません。
{name} // OK(値になる)
{price * 1.1} // OK
{isOpen ? "開" : "閉"} // OK(三項演算子は式)
{if (isOpen) { ... }} // NG(if は式ではない)
{for (...) { ... }} // NGif や for が書けないのは、それらが値にならないからです。 だから React では、条件分岐に三項演算子や && を使い、繰り返しに map を使います。どちらも式だからです。
jsx-expression.tsx
const name = "さとう";
const price = 1200;
const tags = ["React", "TypeScript"];
export function JsxExpression() {
return (
<ul className="flex flex-col gap-2.5">
{/* 変数をそのまま置ける */}
<li className="rounded-md border p-2.5">{name} さん</li>
{/* 計算もできる。式なら何でもよい */}
<li className="rounded-md border p-2.5">{price * 1.1} 円(税込)</li>
{/* メソッドの呼び出しも式 */}
<li className="rounded-md border p-2.5">{name.length} 文字</li>
{/* 条件による出し分けも、三項演算子なら式として書ける */}
<li className="rounded-md border p-2.5">
{tags.length > 0 ? tags.join(" / ") : "タグなし"}
</li>
</ul>
);
}JSX は値なので、持ち回せる
JSX が値だということを、実際に確かめてみます。 変数に入れることも、配列に入れることもできます。
badge を 2 か所で使い回している
- さとう 新着
- すずき 新着
map が JSX の配列を作っているのも、これと同じことです。 Part 0 でやった「map は新しい配列を返す」が、 そのまま「JSX の配列を返す」になっているだけです。
jsx-value.tsx
// JSX は値なので、変数に入れられる
const badge = <span className="rounded border px-2 py-0.5 text-xs">新着</span>;
// 配列に入れることもできる。これがリスト表示の正体
const rows = ["さとう", "すずき"].map((memberName) => (
<li key={memberName} className="rounded-md border p-2.5">
{memberName} {badge}
</li>
));
export function JsxValue() {
return <ul className="flex flex-col gap-2.5">{rows}</ul>;
}HTML と違うところ
JSX は JavaScript なので、HTML の書き方がそのままでは使えない箇所があります。 数は多くありません。
class ではなく className
class は JavaScript の予約語(クラスを作るための言葉)なので、 属性名として使えません。そのため className になっています。 同じ理由で for は htmlFor です。
属性はキャメルケース
<input onChange={...} maxLength={10} tabIndex={0} />onchange ではなく onChange。 JavaScript のオブジェクトのキーとして書かれるので、 JavaScript の命名にそろえてあります。
タグは必ず閉じる
<br /> // ○ 自分で閉じる
<br> // ✕ エラーになる返せるのはひとつだけ
関数が返せる値はひとつなので、JSX も一番外側はひとつでなければいけません。 ただ、そのために余計な div を増やしたくないときは、 名前のないタグで囲みます。
// 余計な div が増えてしまう
<div>
<p>A</p>
<p>B</p>
</div>
// 画面には何も出ない、まとめるためだけのタグ
<>
<p>A</p>
<p>B</p>
</><> </> は Fragment と呼ばれます。 「まとめたいだけで、要素は増やしたくない」ときに使います。
jsx-expression.tsx
const name = "さとう";
const price = 1200;
const tags = ["React", "TypeScript"];
export function JsxExpression() {
return (
<ul className="flex flex-col gap-2.5">
{/* 変数をそのまま置ける */}
<li className="rounded-md border p-2.5">{name} さん</li>
{/* 計算もできる。式なら何でもよい */}
<li className="rounded-md border p-2.5">{price * 1.1} 円(税込)</li>
{/* メソッドの呼び出しも式 */}
<li className="rounded-md border p-2.5">{name.length} 文字</li>
{/* 条件による出し分けも、三項演算子なら式として書ける */}
<li className="rounded-md border p-2.5">
{tags.length > 0 ? tags.join(" / ") : "タグなし"}
</li>
</ul>
);
}理解できたか確かめる
確認クイズ
JSX の中で if 文が書けないのはなぜ?
確認クイズ
class ではなく className と書くのはなぜ?
jsx-expression.tsx
const name = "さとう";
const price = 1200;
const tags = ["React", "TypeScript"];
export function JsxExpression() {
return (
<ul className="flex flex-col gap-2.5">
{/* 変数をそのまま置ける */}
<li className="rounded-md border p-2.5">{name} さん</li>
{/* 計算もできる。式なら何でもよい */}
<li className="rounded-md border p-2.5">{price * 1.1} 円(税込)</li>
{/* メソッドの呼び出しも式 */}
<li className="rounded-md border p-2.5">{name.length} 文字</li>
{/* 条件による出し分けも、三項演算子なら式として書ける */}
<li className="rounded-md border p-2.5">
{tags.length > 0 ? tags.join(" / ") : "タグなし"}
</li>
</ul>
);
}この章のまとめ
- JSX は HTML ではなく、関数呼び出しに変換される JavaScript
- 結果は値なので、変数にも配列にも入れられる
{ }の中には式しか書けない。 だからifではなく三項演算子、forではなくmapclassNameやキャメルケースは、JavaScript の都合に合わせた結果- 一番外側はひとつだけ。増やしたくないときは
<> </>
jsx-expression.tsx
const name = "さとう";
const price = 1200;
const tags = ["React", "TypeScript"];
export function JsxExpression() {
return (
<ul className="flex flex-col gap-2.5">
{/* 変数をそのまま置ける */}
<li className="rounded-md border p-2.5">{name} さん</li>
{/* 計算もできる。式なら何でもよい */}
<li className="rounded-md border p-2.5">{price * 1.1} 円(税込)</li>
{/* メソッドの呼び出しも式 */}
<li className="rounded-md border p-2.5">{name.length} 文字</li>
{/* 条件による出し分けも、三項演算子なら式として書ける */}
<li className="rounded-md border p-2.5">
{tags.length > 0 ? tags.join(" / ") : "タグなし"}
</li>
</ul>
);
}