😳
Reactでfalsyな値を表示制御する方法(0とNaNがカギ)
以下のようなコンポーネントで、「値を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