総合 注文ウィジェット完成
師範 / 目安 45分
陽葵さんが両手を膝に置いて、まっすぐこちらを見ています。「リニューアルの目玉! テイクアウト注文ウィジェット——メニューを選んで、数量入れて、合計が出て、確認画面まで。お願い、これができたらうちは商店街一のモダンカフェよ!」
道場の10問目、最後の依頼です。
新しく覚える書き方はありません。ここまでの9問で使った道具を、1つのまとまりに組み上げるだけです。ただし今回は、これまででいちばんstate の設計が効く問題です。
一番の分かれ道は「合計金額を state に持つかどうか」です。持ちたくなります。注文が増えたら足して、減ったら引いて。しかしそれをやると、注文の配列と合計という同じことを表す値が2つ画面に住むことになります。片方だけ更新し忘れた瞬間、画面は嘘をつきます。
React の答えははっきりしています。他の state から計算で出せる値は、state にしない。 描くたびに計算してください。
JavaScript (JSX)
const total = items.reduce((sum, item) => sum + item.price * item.qty, 0);これは毎回の描画で走りますが、それでいいのです。計算し直すコストより、2つの値がずれる事故のほうがずっと高くつきます。state に持つのは「これが変われば他がすべて決まる」という最小の情報だけ、と覚えてください。今回それは注文の配列1つです。
もう1つの山場は、配列の state を更新することです。ここで items.push(...) と書くと動きません。React は前の値と新しい値が同じものかどうかで変化を見分けるので、中身をその場で書きかえても「同じ配列だ」と判断され、画面が変わらないのです。新しい配列を作って渡すのが決まりです。
JavaScript (JSX)
setItems([...items, newItem]);数量を変えるときは map を使い、対象のものだけ差し替えた新しい配列を返します。
JavaScript (JSX)
setItems(items.map((item) => (item.id === id ? { ...item, qty: item.qty + 1 } : item)));{ ...item, qty: ... } は「その品物のコピーを作って、qty だけ上書きしたもの」です。元の物には触れません。
そして同じ品物を2回押したときの扱いを決めておいてください。行が2つに増えるのではなく、すでにある行の数量が増えるのが自然です。押されたときにまず「その品物がもう入っているか」を探し、あれば数量を増やし、無ければ数量1で追加する、という2つの道を作ります。
最後は確認画面です。注文ボタンを押したら、className が confirm の枠を出して、点数と合計を読み取れる文にします。これも条件表示です。中身が空のときはボタンを押しても確認を出さないでください。
完成条件
注文に入れる
- 注文の中身を
useStateで配列として持つ。合計金額は state にしない - 各メニューの
classNameがadd-btnのボタンを押すと、その品物が数量1で注文に入る - すでに入っている品物のボタンをもう一度押したら、行を増やさずその行の数量を1増やす
- 注文の各行は
classNameがlineの要素とし、品名と数量が読み取れる形にする
数量と合計
- 各行の
classNameがqty-upのボタンで数量を1増やし、qty-downで1減らす - 数量が0になった品物は注文から取り除く
classNameがtotalの要素に、単価かける数量を全部足した合計を「合計 1000円」の形で出す- 注文が空のときは
classNameがemptyの要素に、まだ何も選ばれていないことを示す文を出す
確認
classNameがorder-btnのボタンを押すとclassNameがconfirmの枠が現れ、点数と合計金額が読み取れる文を出す- 注文が空のときは、注文ボタンを押しても確認の枠を出さない
進め方
一息に書こうとすると必ず崩れます。順番があります。
- まず追加だけを作る。押したら行が増えて、品名が出るところまで
- 次に同じ品物を2回押したときに数量が増えるようにする
- 合計の計算を足す
- 数量の増減と、0での取り除きを作る
- 最後に確認画面を出す
1つ動くたびに画面で押して確かめて、次に進んでください。4番目までが本体で、5番目は問7で作ったものと同じ形です。
メニューのデータと見た目は用意してあります。書くのは App.jsx の中身だけです。
ヒントは3段階で、①方針、②使う構文、③部分解の順に出ます。1つも開けずに通せたら、その問題は自分のものです。
これで10問すべてです。陽葵さんが自分でメニューを3つ押し、数量を増やし、合計が跳ね上がるのを見て、注文ボタンを押しました。確認の枠が現れると、両手で頬をおさえて言いました。「商店街一、いただきました!」
師範が奥から一枚の紙を持って出てきます。そこには React道場・師範代を允許する と書かれていました。1つのカードを部品にするところから始めて、いまあなたは、state の置き場所を自分で決め、動く注文フローを白紙から組み上げられます。
ヒント
前のヒントを開くと次が開きます。開かずに解けると未開封クリアです