条件付きレンダー
様々な条件によって、コンポーネントに表示させる内容を変化させたいことがあります。React では、JavaScript の if
文や &&
、? :
演算子などの構文を使うことで、JSX を条件付きでレンダーできます。
このページで学ぶこと
- 条件に応じて異なる JSX を返す方法
- JSX の一部を条件によって表示したり除外したりする方法
- React コードベースでよく使われる条件式のショートカット記法
条件を満たす場合に JSX を返す
例えば、複数の Item
をレンダーする PackingList
コンポーネントがあり、各 Item
に梱包が終わっているかどうか表示させたいとしましょう。
function Item({ name, isPacked }) { return <li className="item">{name}</li>; } export default function PackingList() { return ( <section> <h1>Sally Ride's Packing List</h1> <ul> <Item isPacked={true} name="Space suit" /> <Item isPacked={true} name="Helmet with a golden leaf" /> <Item isPacked={false} name="Photo of Tam" /> </ul> </section> ); }
複数の Item
コンポーネントのうち一部のみで isPacked
プロパティが false
ではなく true
になっていることに注意してください。目的は、isPacked={true}
の場合にのみチェックマーク (✔) を表示させることです。
これは if
/else
文を使って、以下のように書くことができます。
if (isPacked) {
return <li className="item">{name} ✔</li>;
}
return <li className="item">{name}</li>;
isPacked
プロパティが true
だった場合、このコードは異なる JSX ツリーを返します。この変更により、一部のアイテムの末尾にチェックマークが表示されます。
function Item({ name, isPacked }) { if (isPacked) { return <li className="item">{name} ✔</li>; } return <li className="item">{name}</li>; } export default function PackingList() { return ( <section> <h1>Sally Ride's Packing List</h1> <ul> <Item isPacked={true} name="Space suit" /> <Item isPacked={true} name="Helmet with a golden leaf" /> <Item isPacked={false} name="Photo of Tam" /> </ul> </section> ); }
それぞれの場合に返される内容を編集してみて、表示がどのように変化するか確認しましょう。
条件分岐ロジックを実装するために JavaScript の if
や return
文を使ったことに着目してください。React では、制御フロー(条件分岐など)は JavaScript で処理されます。
null
を使って何も返さないようにする
場合によっては、何もレンダーしたくないことがあります。例えば、梱包済みの荷物は一切表示したくない、という場合です。コンポーネントは常に何かを返す必要があります。このような場合、null
を返すことができます。
if (isPacked) {
return null;
}
return <li className="item">{name}</li>;
isPacked
が true
の場合、コンポーネントは「何も表示しない」という意味で null
を返します。それ以外の場合、レンダーする JSX を返します。
function Item({ name, isPacked }) { if (isPacked) { return null; } return <li className="item">{name}</li>; } export default function PackingList() { return ( <section> <h1>Sally Ride's Packing List</h1> <ul> <Item isPacked={true} name="Space suit" /> <Item isPacked={true} name="Helmet with a golden leaf" /> <Item isPacked={false} name="Photo of Tam" /> </ul> </section> ); }
実際には、レンダーしようとしている開発者を混乱させる可能性があるため、コンポーネントから null
を返すことは一般的ではありません。代わりに、親コンポーネント側の JSX で条件付きでコンポーネントを含めたり除外したりすることが多いでしょう。以下はその方法です。
条件付きで JSX を含める
前の例では、コンポーネントが複数の JSX ツリーのうちどれを返すのか(あるいは何も返さないのか)をコントロールしていました。しかし、レンダー出力に重複があることに気付かれたでしょう。
<li className="item">{name} ✔</li>
これは以下とほとんど同じです。
<li className="item">{name}</li>
どちらの分岐も <li className="item">...</li>
を返しています。
if (isPacked) {
return <li className="item">{name} ✔</li>;
}
return <li className="item">{name}</li>;
この重複に実害はありませんが、コードの保守性は悪化してしまいます。たとえば className
を変更したくなったら? コード内の 2 か所で変更が必要になってしまいますよね。このような状況では、条件付きで小さな JSX を含めることで、コードをより DRY に保つことができます。
条件 (三項) 演算子 (? :
)
JavaScript には、条件式を書くためのコンパクトな構文があります。それが条件演算子または「三項 (ternary) 演算子」と呼ばれるものです。
以下のコードは:
if (isPacked) {
return <li className="item">{name} ✔</li>;
}
return <li className="item">{name}</li>;
代わりに以下のように書くことができます:
return (
<li className="item">
{isPacked ? name + ' ✔' : name}
</li>
);
これは「isPacked
が true なら name + ' ✔'
をレンダーし、それ以外 (:
) の場合は name
をレンダーする」というように読んでください。
さらに深く知る
オブジェクト指向プログラミングのバックグラウンドをお持ちの場合、2 つの例の一方では <li>
の「インスタンス」が 2 つ作られるため、これらがわずかに異なると考えてしまうかもしれません。しかし JSX 要素は内部に状態を持たず、実際の DOM 要素でもないため、「インスタンス」ではありません。JSX は軽量な「説明書き」であり設計図のようなものです。従って上記の 2 つの例は実際に完全に同等です。Preserving and Resetting State を参照してください。
次に、梱包済みのアイテムを、取り消し線を表示する <del>
のような別のタグで囲みたいとしましょう。このような場合、true と false のそれぞれの場合に対応する改行や括弧を追加することで、ネストされた JSX を読みやすくすることができます。
function Item({ name, isPacked }) { return ( <li className="item"> {isPacked ? ( <del> {name + ' ✔'} </del> ) : ( name )} </li> ); } export default function PackingList() { return ( <section> <h1>Sally Ride's Packing List</h1> <ul> <Item isPacked={true} name="Space suit" /> <Item isPacked={true} name="Helmet with a golden leaf" /> <Item isPacked={false} name="Photo of Tam" /> </ul> </section> ); }
これはシンプルな条件分岐の場合にはうまく動きますが、使いすぎないようにしましょう。条件のためのマークアップが増えすぎてコンポーネントが見づらくなった場合は、見やすくするために子コンポーネントを抽出することを検討してください。React ではマークアップはプログラミングコードの一種ですので、変数や関数といった道具を利用して複雑な式を読みやすく整頓することができます。
論理 AND 演算子 (&&
)
もうひとつよく使われるショートカットは、JavaScript の論理 AND (&&
) 演算子です。React コンポーネント内で、条件が真の場合に JSX をレンダーし、それ以外の場合は何もレンダーしないという場合にしばしば使用されます。&&
を使用すると、isPacked
が true
の場合にのみチェックマークを条件付きでレンダーできます。
return (
<li className="item">
{name} {isPacked && '✔'}
</li>
);
これは「isPacked
なら (&&
)、チェックマークをレンダーし、それ以外の場合には何もレンダーしない」のように読んでください。
以下が完全に動作する例です:
function Item({ name, isPacked }) { return ( <li className="item"> {name} {isPacked && '✔'} </li> ); } export default function PackingList() { return ( <section> <h1>Sally Ride's Packing List</h1> <ul> <Item isPacked={true} name="Space suit" /> <Item isPacked={true} name="Helmet with a golden leaf" /> <Item isPacked={false} name="Photo of Tam" /> </ul> </section> ); }
JavaScript の && 式 は、左側(条件)が true
である場合、右側(今回の場合はチェックマーク)の値を返します。しかし、条件が false
である場合、式全体が false
になります。React は、false
を JSX ツリーの「穴」と見なし、null
や undefined
と同様に、何もレンダーしません。
条件付きで JSX を変数に割り当てる
上記のようなショートカットを使って簡潔にコードを記述するのが難しいと感じた場合は、if
文と変数を使用してみてください。let
で定義した変数は再代入も可能ですので、最初に表示したいデフォルトの値 (name) を指定します。
let itemContent = name;
そして if
文を使って、isPacked
が true
の場合のみ itemContent
に JSX 式を再割り当てします。
if (isPacked) {
itemContent = name + " ✔";
}
波括弧は「JavaScript への窓口」です。波括弧を使って JSX ツリーに変数を埋め込むことで、さきほど計算した値を JSX 内にネストすることができます。
<li className="item">
{itemContent}
</li>
このスタイルは最も長くなりますが、同時に最も柔軟です。以下が全体像です。
function Item({ name, isPacked }) { let itemContent = name; if (isPacked) { itemContent = name + " ✔"; } return ( <li className="item"> {itemContent} </li> ); } export default function PackingList() { return ( <section> <h1>Sally Ride's Packing List</h1> <ul> <Item isPacked={true} name="Space suit" /> <Item isPacked={true} name="Helmet with a golden leaf" /> <Item isPacked={false} name="Photo of Tam" /> </ul> </section> ); }
前述の通り、これはテキストのみでなく任意の JSX に対して使えます。
function Item({ name, isPacked }) { let itemContent = name; if (isPacked) { itemContent = ( <del> {name + " ✔"} </del> ); } return ( <li className="item"> {itemContent} </li> ); } export default function PackingList() { return ( <section> <h1>Sally Ride's Packing List</h1> <ul> <Item isPacked={true} name="Space suit" /> <Item isPacked={true} name="Helmet with a golden leaf" /> <Item isPacked={false} name="Photo of Tam" /> </ul> </section> ); }
JavaScript に慣れていない場合、これだけ多様なスタイルがあると最初は圧倒されるかもしれません。しかし、これらを学ぶことは、React コンポーネントだけでなく、あらゆる JavaScript コードを読み書きできるようになるのにも役立ちます。最初は好みのスタイルを選んでスタートし、他のスタイルの仕組みを忘れた場合は、再度このリファレンスを参照してください。
まとめ
- React では、JavaScript を使用して分岐ロジックを制御する。
if
文を使用して、条件に応じて JSX 式を返すことができる。- JSX 内で中身を条件付きで変数に保存し、波括弧を使用して他の JSX 内に含めることができる。
- JSX 内の
{cond ? <A /> : <B />}
は、「cond
であれば<A />
をレンダーし、そうでなければ<B />
をレンダーする」という意味である。 - JSX 内の
{cond && <A />}
は、「cond
であれば<A />
をレンダーし、そうでなければ何もレンダーしない」という意味である。 - これらのショートカットは一般的だが、プレーンな
if
が好きなら必ずしも使わなくて良い。
チャレンジ 1/3: ? :
を使って未梱包アイコンを表示
条件演算子 (cond ? a : b
) を使って、isPacked
が true
でない場合は ❌ をレンダーするようにしてください。
function Item({ name, isPacked }) { return ( <li className="item"> {name} {isPacked && '✔'} </li> ); } export default function PackingList() { return ( <section> <h1>Sally Ride's Packing List</h1> <ul> <Item isPacked={true} name="Space suit" /> <Item isPacked={true} name="Helmet with a golden leaf" /> <Item isPacked={false} name="Photo of Tam" /> </ul> </section> ); }