Part 0 · React の前に
truthy / falsy と && || ??
条件によって出し分けるための土台
React で「件数が 0 のときは何も出さない」と書いたはずなのに、 画面に 0 だけがぽつんと表示される。 これは初心者が必ず一度は遭遇するバグです。
原因は && という記号の性質にあります。これは「かつ」ではなく、値を返す演算子だからです。
この章では、そのからくりを先に潰しておきます。
JavaScript は何でも真偽に変換する
if の中に true / false 以外を書いても、JavaScript は文句を言いません。 勝手に「真っぽいか、偽っぽいか」に変換して判断します。
このとき偽として扱われる値は 6 つだけです。 これ以外は全部、真として扱われます。
空の配列も空のオブジェクトも「真」になる
偽として扱われる(これで全部)
- false
- 0
- ""
- null
- undefined
- NaN
真として扱われる(間違えやすいもの)
- []
- {}
- "0"
- "false"
- -1
- " "
falsy.ts
// 偽として扱われる値は、この 6 つだけ
export const falsyValues = [false, 0, "", null, undefined, NaN];
// それ以外は全部「真」として扱われる。
// 中身が空でも、文字が "0" や "false" でも真になる
export const truthyButSurprising = [[], {}, "0", "false", -1, " "];&& と || は「値を返す」
ここが本題です。&& と || は、true か false を返すのではありません。 左右どちらかの値そのものを返します。
A && B… A が偽なら A を返す。真なら B を返すA || B… A が真なら A を返す。偽なら B を返すA ?? B… A がnullかundefinedのときだけ B を返す
0 のときの結果に注目
- count && "あり"→0
- stock && "あり"→"あり"
- keyword || "デフォルト"→"デフォルト"
- count || "デフォルト"→"デフォルト"
- count ?? "デフォルト"→0
- nickname ?? "デフォルト"→"デフォルト"
count が 0 のとき、count && "あり" の結果は false ではなく 0 です。 左が偽だったので、そのまま左の値が返っています。
operators.ts
/*
&& は 左が偽ならその左の値を返し、真なら右の値を返す
|| は 左が真ならその左の値を返し、偽なら右の値を返す
?? は 左が null か undefined のときだけ右の値を返す
*/
// 実際のデータと同じように、変数に入った値で試す
const count: number = 0;
const stock: number = 5;
const keyword: string = "";
const nickname: string | null = null;
export const examples = [
{ code: 'count && "あり"', result: count && "あり" },
{ code: 'stock && "あり"', result: stock && "あり" },
{ code: 'keyword || "デフォルト"', result: keyword || "デフォルト" },
{ code: 'count || "デフォルト"', result: count || "デフォルト" },
{ code: 'count ?? "デフォルト"', result: count ?? "デフォルト" },
{ code: 'nickname ?? "デフォルト"', result: nickname ?? "デフォルト" },
];これが「画面に 0 が出る」の正体
React では、条件によって表示を出し分けるときにこう書きます。
{items.length && <p>{items.length} 件あります</p>}件数が 3 なら、3 && <p>...</p> で右側が返り、 文章が表示されます。ここまでは意図どおりです。
ところが件数が 0 のとき、この式は 0 を返します。そして React は、数値の 0 を画面に表示します。 非表示にしたかったのに、0 という文字が残るのはこのためです。
// ✕ 0 が画面に出る
{items.length && <p>{items.length} 件あります</p>}
// ○ 比較して true / false にしてから渡す
{items.length > 0 && <p>{items.length} 件あります</p>}false は React が画面に出さないと決めている値なので、 何も表示されません。
operators.ts
/*
&& は 左が偽ならその左の値を返し、真なら右の値を返す
|| は 左が真ならその左の値を返し、偽なら右の値を返す
?? は 左が null か undefined のときだけ右の値を返す
*/
// 実際のデータと同じように、変数に入った値で試す
const count: number = 0;
const stock: number = 5;
const keyword: string = "";
const nickname: string | null = null;
export const examples = [
{ code: 'count && "あり"', result: count && "あり" },
{ code: 'stock && "あり"', result: stock && "あり" },
{ code: 'keyword || "デフォルト"', result: keyword || "デフォルト" },
{ code: 'count || "デフォルト"', result: count || "デフォルト" },
{ code: 'count ?? "デフォルト"', result: count ?? "デフォルト" },
{ code: 'nickname ?? "デフォルト"', result: nickname ?? "デフォルト" },
];|| と ?? の使い分け
初期値を用意したいとき、つい || を使ってしまいますが、 これも 0 で事故が起きます。
const count = 0;
count || 10; // 10 ← 0 は偽なので置き換えられてしまう
count ?? 10; // 0 ← null / undefined でないのでそのまま「値が入っていないときだけ初期値を使いたい」のであれば、?? を使うのが正解です。|| は 0 や空文字まで「なかったこと」にしてしまいます。
operators.ts
/*
&& は 左が偽ならその左の値を返し、真なら右の値を返す
|| は 左が真ならその左の値を返し、偽なら右の値を返す
?? は 左が null か undefined のときだけ右の値を返す
*/
// 実際のデータと同じように、変数に入った値で試す
const count: number = 0;
const stock: number = 5;
const keyword: string = "";
const nickname: string | null = null;
export const examples = [
{ code: 'count && "あり"', result: count && "あり" },
{ code: 'stock && "あり"', result: stock && "あり" },
{ code: 'keyword || "デフォルト"', result: keyword || "デフォルト" },
{ code: 'count || "デフォルト"', result: count || "デフォルト" },
{ code: 'count ?? "デフォルト"', result: count ?? "デフォルト" },
{ code: 'nickname ?? "デフォルト"', result: nickname ?? "デフォルト" },
];理解できたか確かめる
確認クイズ
0 && '表示' の結果は?
確認クイズ
件数が 0 のときは何も表示したくない。正しい書き方は?
確認クイズ
const count = 0; のとき、count ?? 10 の結果は?
operators.ts
/*
&& は 左が偽ならその左の値を返し、真なら右の値を返す
|| は 左が真ならその左の値を返し、偽なら右の値を返す
?? は 左が null か undefined のときだけ右の値を返す
*/
// 実際のデータと同じように、変数に入った値で試す
const count: number = 0;
const stock: number = 5;
const keyword: string = "";
const nickname: string | null = null;
export const examples = [
{ code: 'count && "あり"', result: count && "あり" },
{ code: 'stock && "あり"', result: stock && "あり" },
{ code: 'keyword || "デフォルト"', result: keyword || "デフォルト" },
{ code: 'count || "デフォルト"', result: count || "デフォルト" },
{ code: 'count ?? "デフォルト"', result: count ?? "デフォルト" },
{ code: 'nickname ?? "デフォルト"', result: nickname ?? "デフォルト" },
];この章のまとめ
- 偽として扱われるのは
false, 0, "", null, undefined, NaNの 6 つだけ。空の配列やオブジェクトは真 &&と||は true / false ではなく値そのものを返す{count && <p>…</p>}は、count が 0 のとき画面に 0 を出す。count > 0 &&と書けば防げる- 初期値を入れたいときは
||ではなく??
falsy.ts
// 偽として扱われる値は、この 6 つだけ
export const falsyValues = [false, 0, "", null, undefined, NaN];
// それ以外は全部「真」として扱われる。
// 中身が空でも、文字が "0" や "false" でも真になる
export const truthyButSurprising = [[], {}, "0", "false", -1, " "];