- React
React条件分岐の書き方|三項演算子・&&・早期リターンと0が表示される原因
Reactの条件分岐とは、props や state の値に応じて、表示する JSX を JavaScript の if・三項演算子・&& などで切り替えることです。 専用の構文はなく、JavaScript の式をそのまま使います。そのため「JSX の波かっこの中に if が書けない」「&& を使ったら画面に 0 が出た」といった、JavaScript の性質に由来するつまずきが起こります。
この記事では、if 早期リターン・三項演算子・&&・switch・オブジェクトマップの5通りを、関数コンポーネントと TypeScript でそのまま貼れる形にまとめました。さらに、false・null・undefined・0・NaN・空文字・空配列などを JSX に置いたとき、画面に何が出るかを実際に動かして一覧表にし、「0 が表示される」現象を再現して3通りの直し方を示します。出力は React 19.3.0(一部は 18.3.1 でも確認)、TypeScript 7.0.2、Node.js 22.22.2 と jsdom 30.1.1 で得たものです。
条件分岐の早見表
| 書き方 | 形 | 向いている場面 | 読みやすさの目安 |
|---|---|---|---|
| if の早期リターン | if (条件) return ...; |
読み込み中・エラー・空など、画面全体を切り替える | 条件が増えても上から順に読める |
| 三項演算子 | 条件 ? A : B |
AかBのどちらかを必ず出す | 1段までは読みやすい。入れ子は避ける |
| && | 条件 && A |
条件を満たすときだけ出す(出さないときは何も無し) | 短い。左辺を真偽値にするのが前提 |
| switch | switch (status) { case ... } |
3つ以上の状態を分ける | 状態が縦に並び、書き漏れを型で検出できる |
| オブジェクトマップ | LABEL[status] |
値と表示が1対1で対応する | 対応表として一目で読める |
| 変数に入れる | let content; if (...) content = ... |
条件が複雑で、JSX の一部だけを変えたい | 計算と表示を分けられる |
迷ったら「全体を切り替えるなら早期リターン、二択なら三項演算子、出すか出さないかなら &&、3つ以上なら switch かオブジェクトマップ」 と覚えておくと選びやすくなります。
本記事の内容は、ご自由にお使いください。
ご利用の際は、出典として本ページへのリンクを記載いただけますようお願いします。
(記載例)出典:株式会社RJC「React条件分岐の書き方|三項演算子・&&・早期リターンと0が表示される原因」
5通りの書き方をコピペできる形で
次のコードは1ファイルにまとめてあり、そのまま貼って使えます。tsc --noEmit(strict)でエラーが出ないことを確認しています。
import type { ReactNode } from "react";
type Status = "loading" | "error" | "empty" | "success";
type Props = { status: Status; items: string[]; isAdmin: boolean; count: number };
// 1. if の早期リターン:画面全体を切り替える
export function TaskList({ status, items }: Props) {
if (status === "loading") return <p>読み込み中...</p>;
if (status === "error") return <p role="alert">読み込めませんでした</p>;
if (items.length === 0) return <p>タスクはまだありません</p>;
return (
<ul>
{items.map((item) => (
<li key={item}>{item}</li>
))}
</ul>
);
}
// 2. 三項演算子:AかBのどちらかを必ず出す
export function LoginButton({ isLoggedIn }: { isLoggedIn: boolean }) {
return <button>{isLoggedIn ? "ログアウト" : "ログイン"}</button>;
}
// 3. &&:条件を満たすときだけ出す(左辺は必ず boolean にする)
export function Badge({ count, isAdmin }: Props) {
return (
<header>
{count > 0 && <span>未読 {count} 件</span>}
{isAdmin && <a href="/admin">管理画面</a>}
</header>
);
}
// 4. switch:3つ以上の状態を分ける(never で書き漏れを検出)
export function StatusMessage({ status }: { status: Status }) {
switch (status) {
case "loading":
return <p>読み込み中...</p>;
case "error":
return <p role="alert">読み込めませんでした</p>;
case "empty":
return <p>データがありません</p>;
case "success":
return <p>完了しました</p>;
default: {
const unreachable: never = status;
return unreachable;
}
}
}
// 5. オブジェクトマップ:値と表示の対応表にする
const STATUS_LABEL: Record<Status, ReactNode> = {
loading: <p>読み込み中...</p>,
error: <p role="alert">読み込めませんでした</p>,
empty: <p>データがありません</p>,
success: <p>完了しました</p>,
};
export function StatusLabel({ status }: { status: Status }) {
return <>{STATUS_LABEL[status]}</>;
}
// 6. 変数に入れてから出す
export function Greeting({ hour }: { hour: number }) {
let message: string;
if (hour < 11) message = "おはようございます";
else if (hour < 18) message = "こんにちは";
else message = "こんばんは";
return <p>{message}</p>;
}
それぞれに値を渡して描画した HTML です(React 19.3.0)。
TaskList loading <p>読み込み中...</p>
TaskList error <p role="alert">読み込めませんでした</p>
TaskList success [] <p>タスクはまだありません</p>
TaskList success [掃除,買い物] <ul><li>掃除</li><li>買い物</li></ul>
LoginButton true <button>ログアウト</button>
LoginButton false <button>ログイン</button>
Badge count=0 isAdmin=false <header></header>
Badge count=3 isAdmin=true <header><span>未読 3 件</span><a href="/admin">管理画面</a></header>
StatusMessage empty <p>データがありません</p>
StatusLabel error <p role="alert">読み込めませんでした</p>
Greeting 9 <p>おはようございます</p>
Greeting 20 <p>こんばんは</p>
Badge に count=0 を渡しても <header></header> のままで、0 は表示されていません。左辺を count > 0 という比較式にしているためです。この点は後半で詳しく扱います。
JSXの中にifが書けない理由
JSX の波かっこ { } の中に書けるのは式(値になるもの)だけです。if や for、switch は「文」なので、そのままでは置けません。
export function Bad({ status }: { status: string }) {
return (
<div>
{if (status === "loading") { <p>読み込み中</p> }}
</div>
);
}
tsc --noEmit の出力です。
art/c2_err2.tsx(4,8): error TS1109: Expression expected.
art/c2_err2.tsx(4,50): error TS1381: Unexpected token. Did you mean `{'}'}` or `}`?
「Expression expected(式が必要です)」と表示されます。 直し方は次の3つのどれかです。
| 直し方 | 書き方 |
|---|---|
| return より前で if を使う | 早期リターン、または変数に入れてから JSX に置く |
| 式で書ける形に変える | 三項演算子、&& |
| 別のコンポーネントや関数に切り出す | 切り出した先で if や switch を使う |
JSXに置いた値は画面にどう出るか(実行結果つき)
条件分岐でつまずく原因の多くは、「その値を JSX に置いたら何が描画されるか」を知ることで解消できます。<div>{値}</div> の形で実際に描画し、できあがった HTML を調べました。
| JSX に置いた値 | 描画された HTML | 画面の見え方 | JavaScript での真偽 |
|---|---|---|---|
false |
<div></div> |
何も出ない | falsy |
true |
<div></div> |
何も出ない | truthy |
null |
<div></div> |
何も出ない | falsy |
undefined |
<div></div> |
何も出ない | falsy |
0 |
<div>0</div> |
0 と出る | falsy |
-0 |
<div>0</div> |
0 と出る | falsy |
NaN |
<div>NaN</div> |
NaN と出る(コンソールに警告も出る) | falsy |
0n(BigInt) |
<div>0</div> |
0 と出る | falsy |
""(空文字) |
<div></div> |
何も出ない | falsy |
"0"(文字列) |
<div>0</div> |
0 と出る | truthy |
"false"(文字列) |
<div>false</div> |
false と出る | truthy |
[](空配列) |
<div></div> |
何も出ない | truthy |
[0] |
<div>0</div> |
0 と出る | truthy |
[false, null] |
<div></div> |
何も出ない | truthy |
{}(オブジェクト) |
エラー | 描画が止まる | truthy |
| 関数 | <div></div> |
何も出ない(コンソールに警告) | truthy |
false から NaN までの7行は React 18.3.1 でも同じ結果でした。オブジェクトを置いたときのエラー文は次のとおりです。
Objects are not valid as a React child (found: object with keys {}). If you meant to render a collection of children, use an array instead.
Date オブジェクトも同じ種類のエラー(found: [object Date])になりました。日付は文字列に変換してから置きます。
この表のポイントは次の2つです。
- React が「何も描画しない」のは false・true・null・undefined・空文字・空配列です。
- 0・NaN・0n は JavaScript では falsy なのに、React は数値として描画します。 ここが「0 が表示される」の原因です。
コンポーネントが返す値の場合
コンポーネントの return に同じ値を置いたときも、同じ規則でした(React 19.3.0 と 18.3.1 の両方で確認)。
| return した値 | 描画結果 |
|---|---|
null |
何も出ない |
undefined |
何も出ない |
false |
何も出ない |
0 |
0 と出る |
「このコンポーネントは今回は何も表示しない」と伝えたいときは、意図がはっきり伝わる return null がおすすめです。
「0が表示される」を再現して直す
再現
件数や配列の長さを && の左辺にそのまま置くと起こります。
function List({ items }: { items: string[] }) {
return (
<div>
{items.length && (
<ul>
{items.map((i) => (
<li key={i}>{i}</li>
))}
</ul>
)}
</div>
);
}
items = [] → <div>0</div>
items = ["a", "b"] → <div><ul><li>a</li><li>b</li></ul></div>
配列が空のとき、画面に 0 が出ました。 A && B は「A が falsy なら A そのものを返す」演算子です。items.length が 0 のとき、式全体の値は false ではなく 0 になり、React は 0 を数値として描画します。TypeScript の型チェックではこの書き方はエラーにならないので、目で気づく必要があります。
&& の左辺に置いた値ごとの結果も確かめました。
| 式 | 描画された HTML | 補足 |
|---|---|---|
0 && <p>あり</p> |
<div>0</div> |
0 が出る |
NaN && <p>あり</p> |
<div>NaN</div> |
NaN が出る |
0n && <p>あり</p> |
<div>0</div> |
0 が出る |
"" && <p>あり</p> |
<div></div> |
何も出ない |
null && <p>あり</p> |
<div></div> |
何も出ない |
undefined && <p>あり</p> |
<div></div> |
何も出ない |
false && <p>あり</p> |
<div></div> |
何も出ない |
[] && <p>あり</p> |
<div><p>あり</p></div> |
空配列は truthy なので右辺が出る |
"0" && <p>あり</p> |
<div><p>あり</p></div> |
文字列の "0" は truthy なので右辺が出る |
空文字は今回の環境(ブラウザ向けの react-dom)では何も描画されませんでした。React Native では空文字の扱いが異なると言われますが、今回は未実行です。どの環境でも安心して使えるよう、&& の左辺は真偽値にそろえるのが確実です。
3通りの直し方
// 直し方1:比較式にする(おすすめ)
{items.length > 0 && <ul>...</ul>}
// 直し方2:!! で真偽値に変換する(Boolean(items.length) でも同じ)
{!!items.length && <ul>...</ul>}
// 直し方3:三項演算子にして、出さない側を null と明示する
{items.length ? <ul>...</ul> : null}
| 書き方 | items が空のとき | items が2件のとき |
|---|---|---|
items.length && ...(直す前) |
<div>0</div> |
リストが出る |
items.length > 0 && ... |
<div></div> |
リストが出る |
!!items.length && ... |
<div></div> |
リストが出る |
Boolean(items.length) && ... |
<div></div> |
リストが出る |
items.length ? ... : null |
<div></div> |
リストが出る |
どれも 0 は出なくなりました。選び方の目安は次のとおりです。
| 直し方 | 良いところ | 選ぶ場面 |
|---|---|---|
| 比較式 | 「何件以上で出すか」が文として読める | 件数・長さ・点数など数値の条件 |
!! または Boolean() |
値の種類を問わず使える | 文字列や null かもしれない値をまとめて判定したい |
| 三項演算子 | 出さない側が null と明示される |
後で「無いときの表示」を足す可能性がある |
「&& の左辺には、比較式か boolean 型の変数だけを置く」と決めておくと、この現象は起こらなくなります。 react.dev の「条件付きレンダー」のページ(今回開いて確認)でも、&& の左辺に数値を置かないことが注意点として挙げられています。
空配列は truthy なので長さで判定する
0 とは逆に、[] は truthy です。配列そのものを条件にすると、空でも右辺が描画されます。
{items && <p>データあり</p>} // items が [] でも「データあり」と出る
{items.length > 0 && <p>データあり</p>} // 空なら何も出ない
それぞれの書き方を深く知る
if の早期リターン:正常系を最後に残す
早期リターンは、「先に特別な状態を片づけて、最後に通常の表示を書く」形です。条件の入れ子が深くならず、上から順に読めます。
if (status === "loading") return <p>読み込み中...</p>;
if (status === "error") return <p role="alert">読み込めませんでした</p>;
if (items.length === 0) return <p>タスクはまだありません</p>;
return <ul>...</ul>;
気をつけたいのは、フック(useState や useEffect など)は早期リターンより前に書くことです。フックは毎回同じ順番で呼ばれる必要があり、早期リターンの後ろに置くと、描画のたびに呼ばれる数が変わってしまいます。
// フックの間に早期リターンがある例
function Profile({ user }: { user: { name: string } | null }) {
const [n] = useState(0);
if (!user) return <p>読み込み中...</p>;
const [open] = useState(false); // user の有無で呼ばれたり呼ばれなかったりする
return <p>{user.name}</p>;
}
user を null から値ありに変えたとき、逆に値ありから null に変えたときの結果です(React 19.3.0)。
null → 値あり : Rendered more hooks than during the previous render.
(コンソール)React has detected a change in the order of Hooks called by Profile. ...
値あり → null : Rendered fewer hooks than expected. This may be caused by an accidental early return statement.
2つ目のメッセージには「early return が原因かもしれない」とはっきり書かれています。 直し方は、フックをすべて先頭に集めることです。
function Profile({ user }: { user: { name: string } | null }) {
const [n] = useState(0);
const [open] = useState(false); // フックはすべて早期リターンより前
if (!user) return <p>読み込み中...</p>;
return <p>{user.name}</p>;
}
なお、すべてのフックを早期リターンの後ろに置いた形(先頭にフックが1つも無い形)では、今回は画面は切り替わったものの、コンソールに Internal React error: Expected static flag was missing. というメッセージが出ました。どちらの場合も、フックを先頭に集めれば解消します。ESLint の react-hooks プラグインにはこの書き方を検出するルールがありますが、今回は未実行です。
三項演算子:二択を1行で書く
<button>{isLoggedIn ? "ログアウト" : "ログイン"}</button>
属性の値や文字列の切り替えにも使えます。
<li className={isDone ? "task done" : "task"}>{title}</li>
入れ子にすると読みにくくなるので、3つ以上に分かれるときは switch・オブジェクトマップ・早期リターンに切り替えるのが目安です。
// 読みにくくなりやすい形
{status === "loading" ? <Spinner /> : status === "error" ? <ErrorView /> : <List />}
// 読みやすい形(別コンポーネントに切り出して早期リターン)
function Content({ status }: { status: Status }) {
if (status === "loading") return <Spinner />;
if (status === "error") return <ErrorView />;
return <List />;
}
三項演算子と && では state の残り方が違う
同じ種類のコンポーネントを条件で出し分けるとき、書き方によって state が引き継がれるかどうかが変わります。クリックで数が増える Counter を使い、2回クリックしてから表示を切り替えて確かめました。
function Counter({ label }: { label: string }) {
const [n, setN] = useState(0);
return <button onClick={() => setN(n + 1)}>{label}:{n}</button>;
}
// 書き方A:三項演算子
{isA ? <Counter label="A" /> : <Counter label="B" />}
// 書き方B:&& を2つ並べる
{isA && <Counter label="A" />}
{!isA && <Counter label="B" />}
// 書き方C:三項演算子 + key
{isA ? <Counter key="a" label="A" /> : <Counter key="b" label="B" />}
| 書き方 | 切り替え前 | 切り替え後 | state |
|---|---|---|---|
| A:三項演算子 | A:2 |
B:2 |
引き継がれる |
| B:&& を2つ | A:2 |
B:0 |
リセットされる |
| C:三項演算子 + key | A:2 |
B:0 |
リセットされる |
React は「同じ位置にある同じ種類のコンポーネント」を同じものとして扱います。 三項演算子では A と B が同じ位置に入るので state が残り、&& を2つ並べると別々の位置になるのでリセットされます。入力欄を条件で出し分けたときに「前の入力が残っている」と感じたら、key を付けると意図どおりに切り替わります。
&&:出すか出さないかを短く書く
{isAdmin && <a href="/admin">管理画面</a>}
{count > 0 && <span>未読 {count} 件</span>}
{error !== null && <p role="alert">{error}</p>}
複数の条件を組み合わせるときは、条件に名前を付けると読みやすくなります。
const canEdit = isLoggedIn && isOwner && !isLocked;
return <>{canEdit && <button>編集</button>}</>;
初期値を出したいときの論理ORとnull合体演算子
「値が無ければ別の表示にする」ときは || や ?? を使います。0 や空文字の扱いが異なるので、Node.js で確かめた結果を載せます。
| 値 | 値 || "なし" の結果 |
値 ?? "なし" の結果 |
|---|---|---|
0 |
"なし" |
0 |
"" |
"なし" |
"" |
null |
"なし" |
"なし" |
0 件や空文字も意味のある値として表示したいなら ??、空文字も「無い」とみなしたいなら || を選びます。
switch:状態が3つ以上のとき
switch は文なので JSX の中には置けませんが、コンポーネントの本体で使えば各 case から直接 return できます。TypeScript では、default で never に代入しておくと、状態を増やしたときの書き漏れを型チェックで見つけられます。
type Status = "loading" | "error" | "empty" | "success";
function StatusMessage({ status }: { status: Status }) {
switch (status) {
case "loading":
return <p>読み込み中...</p>;
case "error":
return <p>読み込めませんでした</p>;
case "success":
return <p>完了しました</p>;
default: {
const unreachable: never = status; // "empty" の case を書き忘れている
return unreachable;
}
}
}
art/c2_err.tsx(17,13): error TS2322: Type '"empty"' is not assignable to type 'never'.
書き忘れた状態の名前("empty")がエラー文に出るので、どこを足せばよいかがすぐ分かります。
オブジェクトマップ:対応表として書く
値と表示が1対1で決まるときは、オブジェクトにまとめると対応表のように読めます。Record 型を使うと、キーの書き漏れも検出できます。
const LABEL: Record<Status, ReactNode> = {
loading: <p>読み込み中...</p>,
error: <p>読み込めませんでした</p>,
success: <p>完了しました</p>,
};
art/c2_err.tsx(3,7): error TS2741: Property 'empty' is missing in type '{ loading: React.JSX.Element; error: React.JSX.Element; success: React.JSX.Element; }' but required in type 'Record<Status, ReactNode>'.
文字列やクラス名、アイコンの対応にも向いています。
const STATUS_TEXT: Record<Status, string> = {
loading: "読み込み中",
error: "エラー",
empty: "データなし",
success: "完了",
};
const STATUS_CLASS: Record<Status, string> = {
loading: "badge gray",
error: "badge red",
empty: "badge gray",
success: "badge green",
};
function StatusBadge({ status }: { status: Status }) {
return <span className={STATUS_CLASS[status]}>{STATUS_TEXT[status]}</span>;
}
props を渡して中身を変えたいときは、値をコンポーネント(関数)にします。
const VIEW: Record<Status, (props: { items: string[] }) => ReactNode> = {
loading: () => <p>読み込み中...</p>,
error: () => <p>読み込めませんでした</p>,
empty: () => <p>データがありません</p>,
success: ({ items }) => <ul>{items.map((i) => <li key={i}>{i}</li>)}</ul>,
};
function View({ status, items }: { status: Status; items: string[] }) {
const Component = VIEW[status];
return <Component items={items} />;
}
描画結果です。
StatusBadge success <span class="badge green">完了</span>
View empty <p>データがありません</p>
View success <ul><li>掃除</li></ul>
switchとオブジェクトマップの選び方
| 観点 | switch | オブジェクトマップ |
|---|---|---|
| 各状態で処理や計算が必要 | 向いている | 関数を値にすれば可能 |
| 値と表示が1対1 | 書ける | 向いている(表として読める) |
| 書き漏れの検出 | default で never に代入 |
Record 型 |
| 複数の状態で同じ表示 | case を並べて書ける | 同じ値を複数のキーに書く |
| 範囲の条件(10未満など) | 向かない。if を使う | 向かない。if を使う |
リストや属性の中での条件分岐
条件分岐は、要素を出す・出さないだけでなく、クラス名・属性・リストの絞り込みにも使います。よく使う形を1つのコンポーネントにまとめました。
type Task = { id: number; title: string; done: boolean; due?: string };
export function TaskTable({ tasks, showDone }: { tasks: Task[]; showDone: boolean }) {
// 絞り込みは JSX の外で済ませておく
const visible = showDone ? tasks : tasks.filter((t) => !t.done);
if (visible.length === 0) return <p>表示するタスクはありません</p>;
return (
<ul>
{visible.map((t) => (
<li key={t.id} className={t.done ? "task done" : "task"} aria-checked={t.done}>
{t.title}
{t.due !== undefined && <small>(期限 {t.due})</small>}
<button disabled={t.done} title={t.done ? "完了済みです" : undefined}>
完了にする
</button>
</li>
))}
</ul>
);
}
「掃除(完了)」と「買い物(未完了・期限 10/5)」の2件を渡したときの HTML です。
showDone=true
<ul><li class="task done" aria-checked="true">掃除<button disabled="" title="完了済みです">完了にする</button></li><li class="task" aria-checked="false">買い物<small>(期限 10/5)</small><button>完了にする</button></li></ul>
showDone=false
<ul><li class="task" aria-checked="false">買い物<small>(期限 10/5)</small><button>完了にする</button></li></ul>
完了済みの1件だけ・showDone=false
<p>表示するタスクはありません</p>
| 場所 | 書き方 | 結果から分かること |
|---|---|---|
| クラス名 | className={t.done ? "task done" : "task"} |
三項演算子で文字列を切り替える |
| 真偽値の属性 | disabled={t.done} |
false のときは属性そのものが出力されない |
| 付けたり外したりする属性 | title={条件 ? "文言" : undefined} |
undefined を渡した属性は出力されない |
| リストの絞り込み | filter してから map |
map の中で null を返すより、件数の判定がしやすい |
| 絞り込んだ結果が0件 | 早期リターン | 空のリストの代わりに案内文を出せる |
aria-checked のように aria- で始まる属性は、false を渡しても "false" という文字列で出力されています。属性を付けたくないときは false ではなく undefined を渡す、と覚えておくと使い分けやすくなります。
場面別の選び方
| やりたいこと | 選ぶ書き方 | 例 |
|---|---|---|
| 読み込み中・エラー・空を先に片づけたい | if の早期リターン | if (isLoading) return <Spinner />; |
| 何も表示しないコンポーネントにしたい | return null |
if (!isOpen) return null; |
| 文言やクラス名を二択で切り替えたい | 三項演算子 | isOpen ? "閉じる" : "開く" |
| 条件を満たすときだけ要素を足したい | && | isAdmin && <AdminMenu /> |
| 件数があるときだけ出したい | 比較式 + && | count > 0 && <Badge /> |
| 値が無いときに代わりの文言を出したい | ?? |
name ?? "ゲスト" |
| 状態が3つ以上ある | switch / オブジェクトマップ | LABEL[status] |
| 条件が込み入っている | 変数に入れる、または別コンポーネントに切り出す | const canEdit = ... |
| 切り替え時に入力内容をリセットしたい | key を付ける | <Form key={mode} /> |
よくある質問
Q. 三項演算子と && はどちらを使えばよいですか?
A. 条件を満たさないときにも何かを出すなら三項演算子、満たさないときは何も出さないなら && が読みやすいです。&& を使うときは、左辺を count > 0 のような比較式か boolean 型の値にしておくと、0 が表示されることがなくなります。
Q. 表示しないときは null と空文字のどちらを返せばよいですか?
A. 今回の確認ではどちらも何も描画されませんでしたが、「何も表示しない」という意図がはっきり伝わる null がおすすめです。公式ドキュメントでも、何も描画しない場合は null を返す書き方が紹介されています。
Q. 条件で非表示にするのと、CSS で隠すのはどう違いますか? A. 条件分岐で出さなかった要素は、HTML そのものに存在しません。再び表示すると新しく作られるので、内部の state は初期値に戻ります。CSS で隠した場合は要素が残り続けるので、state や入力内容は保たれます。入力内容を保ちたいタブ切り替えなどは CSS、不要なときは作らなくてよい部品は条件分岐、と使い分けます。
Q. 条件分岐の中でフックを使ってもよいですか?
A. フックは条件分岐や早期リターンより前、コンポーネントの一番上で呼びます。本文で再現したとおり、間に早期リターンがあると Rendered fewer hooks than expected. などのエラーになります。条件ごとに別のフックが必要なら、コンポーネントを分けて、それぞれの中でフックを呼ぶ形にします。
まとめ
- React の条件分岐は JavaScript の式で書く。 JSX の波かっこの中に置けるのは式だけなので、if や switch は return の前か、別コンポーネントで使う
- 全体の切り替えは早期リターン、二択は三項演算子、出すか出さないかは &&、3つ以上は switch かオブジェクトマップ
- false・true・null・undefined・空文字・空配列は何も描画されず、0・NaN・0n は数値として描画される(実行して確認)
- 「0 が表示される」は && の左辺に数値を置いたときに起こる。 比較式にする・
!!を付ける・三項演算子にする、のどれかで直る - フックは早期リターンより前に書く。 間に挟むと
Rendered fewer hooks than expected.などのエラーになる - 三項演算子は同じ位置なので state が引き継がれ、&& を2つ並べるとリセットされる。 リセットしたいときは key を付ける
- TypeScript の
neverとRecordで、状態の書き漏れを型チェックで見つけられる
本記事の内容は、ご自由にお使いください。
ご利用の際は、出典として本ページへのリンクを記載いただけますようお願いします。
(記載例)出典:株式会社RJC「React条件分岐の書き方|三項演算子・&&・早期リターンと0が表示される原因」
株式会社RJCでは、React の条件分岐や JSX の仕組みを仲間と学び合っています。こうした知識を共有しながら、日々技術を磨いています。
株式会社RJC ― SI事業・SES事業・AI駆動開発。RJCは一緒に成長を楽しめる会社です。
WE ARE HIRING
RJCで一緒に開発しながら、
成長を楽しみませんか?
RJCは、Web・モバイル・AIを活用した開発プロジェクトで、テックリードやPM・PMOも活躍するシステム開発会社です。会社を知る、待遇を確かめる、話を聞いてみる。気になるところ見てみてください!
- 127日年間休日
- 12時間平均残業時間
- 毎日ガチャ遊びココロも大切にする福利厚生。アマギフなどの賞品ラインナップ!
ほかにも、チケットレストラン、書籍読み放題、2年ごとの慰労報奨(休暇 or 金一封)、11期連続の黒字決算。