カートreducer
いまの reducer には抜けがある
前のレッスンで書いた reducer は、形としては正しく動いていました。ただしカートの決まりごととしては足りていません。抜けは2つです。
同じスニーカーを2回入れると、行が2つ並びます。fleama のカートで欲しいのは「スニーカー 2点」の1行です。もう1つは、数量を -1 で減らしていくと 0 のまま、あるいはマイナスのままカートに残ることです。
どちらも画面側で頑張るのではなく、reducer の中で決める話です。カートの決まりごとは全部ここに集めます。
既にある行を探してから足す
ADD は「入っていれば増やす、入っていなければ足す」の2通りになります。
find は見つかった要素を返し、見つからなければ undefined を返します。たとえば保存済み商品の確認はこう書けます。
TypeScript (JSX)
const favorite = savedItems.find((item) => item.id === "7");
if (favorite) {
console.log(favorite.title);
}case の中で const を書くときは、波かっこで囲んで変数を使う範囲を区切ります。演習では ADD の波かっこと found の宣言を用意してあります。見つかった行をどう更新するかは、自分で決めて書きます。
0 になったら行ごと外す
CHANGE_QTY は、渡された数量が 0 以下なら REMOVE と同じことをします。
配列から条件に合う要素を残すのが filter、各要素を置き換えるのが map です。たとえば在庫のある商品だけを残し、100円引きの表示用データを作るなら次のように書けます。
TypeScript (JSX)
const inStock = offers.filter((offer) => offer.stock > 0);
const discounted = inStock.map((offer) => ({ ...offer, price: offer.price - 100 }));ボタン側は何も変わりません。押した人は「1つ減らす」と伝えただけで、それが最後の1つだったかどうかは知らなくてよい。判断は reducer が引き受けるという分け方です。
元の配列を書き換えない
reducer で一番やってしまいがちな間違いが、これです。
TypeScript (JSX)
case "ADD":
cart.push({ item: action.item, qty: 1 });
return cart;これは動きません。返しているのが同じ配列なので、React は「変わっていない」と見て描き直しません。画面が更新されないのに、コンソールにも何も出ません。原因を探しにくい事故なので、reducer では map と filter とスプレッドだけを使う、と決めてしまうのが安全です。
演習
ADD と CHANGE_QTY を、カートの決まりごとに合うように直します。