React・データを流しこむ

条件で出し分ける

レアな鳥にだけバッジを出す、説明が無い鳥には別の文を出す——JSXの中で条件を書く方法を整理します。&&で0が表示されてしまう有名な落とし穴と、propsが増えてきたときのまとめ方も扱います。

いま8羽が同じ形で並んでいます。ここに条件を足します。

  • レアな鳥(rareが3以上)にだけ「レア」バッジを出す
  • 説明が空の鳥には「せつめいはじゅんび中」と出す

JSXの中ではif文が使えないので、式で書ける条件分岐を使います。

&&——あるときだけ出す

「条件に合うときだけ出す」は&&が定番です。

{rare >= 3 && <span className="badge">レア</span>}

&&は、左が真なら右を返し、偽なら左を返すという演算子です。返ってきた値がJSXならそれが表示され、falseならReactは何も表示しません

Reactが画面に出さない値は次の4つです。

表示
false / true何も出ない
null何も出ない
undefined何も出ない
00と出る

最後の1行が、次の落とし穴の正体です。

三項演算子——AかBかを出し分ける

「無いときは代わりにこれ」なら三項演算子です。

{memo ? (
  <p className="mt-1 text-sm text-slate-600">{memo}</p>
) : (
  <p className="mt-1 text-sm text-slate-400 italic">せつめいはじゅんび中</p>
)}

条件 ? 真のとき : 偽のとき。JSXが長くなるのでかっこで囲んで改行します。

入れ子にはしないのがコツです。3つ以上に分かれるなら、次の書き方に逃がします。

returnより前でifを使う

JSXのならif文がふつうに書けます。分岐が複雑になったら、変数に入れてから差しこみます。

function RareBadge({ rare }) {
  let label = null
  if (rare >= 3) label = 'レア'
  else if (rare === 2) label = 'ときどき見る'

  return label && <span className="badge">{label}</span>
}

「そもそも何も出さない」ときは、早めにreturnするのがいちばん読みやすくなります。

function BirdCard({ bird }) {
  if (!bird) return null   // データが無いなら何も描かない

  return <div>…</div>
}

nullを返すと、Reactはそのコンポーネントを何も出力しません。「読みこみ中は一覧を出さない」のような分岐でも、この形をよく使います。

条件でクラス名を変える

出し分けるのは要素だけではありません。同じ要素の見た目だけを条件で変えたい——お気に入りのカードだけ色を変える、といった場面です。

classNameも波かっこで書けるので、三項演算子がそのまま使えます。

<div className={isFavorite ? 'bg-amber-50' : 'bg-white'}>

共通のクラスと、条件で変わるクラスを混ぜたいときは、テンプレートリテラルでつなぎます。

<div className={`rounded-2xl p-5 shadow-sm ${isFavorite ? 'bg-amber-50' : 'bg-white'}`}>

propsが増えてきたら、まとめて渡す

いまBirdCardには4つのpropsを渡しています。バッジのためにrareも要るので5つです。並べ続けるとApp.jsxが長くなります。

// これまで
<BirdCard name={bird.name} emoji={bird.emoji} area={bird.area} memo={bird.memo} rare={bird.rare} />

// オブジェクトごと渡す
<BirdCard bird={bird} />

受け取る側で分割代入すれば、中の書き方は変わりません。

function BirdCard({ bird }) {
  const { name, emoji, area, memo, rare } = bird

}

公式ドキュメントも見てみる

ja.react.dev外部サイト条件付きレンダー – React公式の「条件付きレンダー」。「論理AND演算子(&&)」の節に、0が表示されてしまう罠の説明もあります

このレッスンのまとめ

  1. 「あるときだけ出す」は&&、「AかBか」は三項演算子classNameにもそのまま使える
  2. Reactはfalsenullundefinedを表示しないが、0は表示する
  3. だから{配列.length && …}は危険——> 0を付けて真偽値にする
  4. 複雑な分岐はJSXの外でif何も出さないときはreturn null
  5. propsが増えて、しかも元が1つのオブジェクトならbird={bird}とまとめて渡す

次からは章が変わって、画面が動き出します。押したら変わる値——stateの回です。

やってみよう:レアバッジと「せつめいはじゅんび中」

BirdCardに条件分岐を2つ足します。あわせてpropsをオブジェクトごと渡す形に変えます。

  1. src/App.jsx<BirdCard … /><BirdCard key={bird.id} bird={bird} />にする
  2. src/components/BirdCard.jsx{ bird }で受け取り、中で分割代入する
  3. rareが3以上のときだけ「レア」チップを出す(&&
  4. memoが空のときは「せつめいはじゅんび中」を出す(三項演算子)
function BirdCard({ bird }) {
  const { name, emoji, area, memo, rare } = bird

  return (
    <div className="flex gap-4 rounded-2xl bg-white p-5 shadow-sm">
      <span className="text-4xl">{emoji}</span>
      <div>
        <div className="flex items-center gap-2">
          <h2 className="font-bold text-slate-800">{name}</h2>
          <span className="rounded-full bg-sky-100 px-2 py-0.5 text-xs text-sky-700">
            {area}
          </span>
          {rare >= 3 && (
            <span className="rounded-full bg-amber-100 px-2 py-0.5 text-xs font-bold text-amber-700">
              レア
            </span>
          )}
        </div>
        {memo ? (
          <p className="mt-1 text-sm text-slate-600">{memo}</p>
        ) : (
          <p className="mt-1 text-sm text-slate-400 italic">せつめいはじゅんび中</p>
        )}
      </div>
    </div>
  )
}

export default BirdCard
8羽のカードのうち、シマエナガとハクチョウにオレンジ色の「レア」チップが付いている。ハシブトガラスの説明欄には薄い文字で「せつめいはじゅんび中」と表示されている
レアが2羽、説明が無いのが1羽。データを変えれば表示も変わることを、birds.jsrareをいじって確かめてみてください

rareの数字を書きかえると、バッジの付く鳥が変わります。画面を直さずにデータだけで見た目が変わる——この感覚が、Reactの気持ちよさです。

よくある質問

JSXの中でif文は使えますか?
波かっこの中には式しか書けないので使えません。三項演算子や&&を使うか、returnより前でif文を書いて変数に入れるか、条件に合わないときは早めにreturnします。
&&を使うと0が表示されてしまうのはなぜですか?
&&は左側が偽のとき左側の値をそのまま返すためです。0は偽として扱われますが、Reactは0を画面に表示できてしまうので、数字の0だけが残ります。条件をbirds.length > 0のように真偽値へ直せば防げます。
何も表示したくないときは何を返せばいいですか?
nullを返します。Reactはnull・undefined・false・trueを画面に何も出しません。空文字を返すより意図がはっきりします。