😳

Reactでfalsyな値を表示制御する方法(0とNaNがカギ)

2025/03/08に公開

以下のようなコンポーネントで、「値をNaNにする」というボタンを押した場合に、
どのような表示になるでしょうか?

import { useState } from "react";

export default function App() {
  const [count, setCount] = useState<number>(0);

  const handleClick = () => {
    // 負の数の平方根なので、必ずNaNになる。
    setCount(Math.sqrt(-1));
  };

  return (
    <div>
      <button onClick={handleClick}>値をNaNにする</button>
      <p>現在の数値: {count && <span>{count}</span>}</p>
    </div>
  );
}

正解は、NaNと表示されます。

表示されないと思った方もいらっしゃるかもしれませんが、
上記のコードの表示制御だと0とNaNはfalsyですが表示されます。

※直感的には0は表示されてNaNは表示されないと思うのではないでしょうか、、、
(少なくとも私はそう思います。)
この辺りの挙動、初めて遭遇した時に不思議に思いました。

Reactにおけるfalsyな値の画面上の表示

よくありがちな、{ foo && <span>{foo}</span>}のような表示制御で、
実際にfalsyな値がどのように扱われるのか見てみます。

※falsyな値は、以下になります。
mdnにfalsyな値として記載されているものを全て動作確認することとします。

  • null
  • undefined
  • false
  • NaN
  • 0
  • -0
  • 0n
  • 空文字
  • document.all

以下のようなコードで確認できます。

export default function App() {
  const values = [
    { label: "null", value: null },
    { label: "undefined", value: undefined },
    { label: "false", value: false },
    { label: "NaN", value: NaN },
    { label: "0", value: 0 },
    { label: "-0", value: -0 },
    { label: "0n (BigInt)", value: 0n },
    { label: '"" (空文字)', value: "" },
    { label: "document.all", value: document.all },
  ];

  return (
    <div>
      <h2>JSX における各値の表示検証</h2>
      <table border={1}>
        <thead>
          <tr>
            <th></th>
            <th>{`{value}`}</th>
            <th>{`{value && <span>{value}</span>}`}</th>
          </tr>
        </thead>
        <tbody>
          {values.map(({ label, value }, index) => (
            <tr key={index}>
              <td>{label}</td>
              <td>{`${value}`}</td>
              <td>{value && <span>{`${value}`}</span>}</td>
            </tr>
          ))}
        </tbody>
      </table>
    </div>
  );
}

実際に画面を表示すると以下のようになり、
0、-0、NaNだけがfalsyな値の中でも表示されることがわかります。

0やNaNの表示を制御するにはどうすればよいか?

先ほどの検証で、valueがfalseの場合は表示されないとわかりました。
なので、表示の判定をするときに二重否定を用いてfalseに変換すれば良いです。

※先述のコードの差分を表すと以下のようになります。
二重否定をすることで、変数を強制的に論理値に変換します。

+    <td>{value && <span>{`${value}`}</span>}</td>
-    <td>{!!value && <span>{`${value}`}</span>}</td>

0は表示させたいけれどNaNは表示させたくないという場合は、
以下のように0だけは表示させるような条件を書きます。

+    <td>{!!value && <span>{`${value}`}</span>}</td>
-    <td>{!!value || (value === 0 && <span>{`${value}`}</span>)}</td>

Discussion