コース一覧
React道場 ハレノヒ珈琲をモダン化する10問
総合 注文ウィジェット完成

React道場 ハレノヒ珈琲をモダン化する10問

React の基本を終えた人が、白紙から部品を組み立てる演習専用コースです。解説はありません。依頼と完成条件だけを読み、自分で設計します。手が止まったときのために、方針・使う構文・部分解の3段階のヒントを各問に用意しています。props を受ける部品から始まり、state、条件付きのクラス、map での描画、絞り込み、制御コンポーネント、入力の検証を経て、最後は部品の分割と注文ウィジェットの完成まで、10問で React の主要な考え方を一巡します。1問15分から45分、全10問で約5時間です。React入門を終えて「写経はできるが白紙からは書けない」と感じている方に向いています。

1
初段
01. MenuCard部品を作れ15分
02. いいねボタン15分
03. ダークモード切替(React版)20分
04. メニュー一覧をmapで描画せよ20分
2
中段
01. カテゴリタブで絞り込め25分
02. 予約フォームを制御せよ25分
03. 入力エラーを表示せよ30分
04. 営業中バッジと時計30分
3
師範
01. 肥大部品を分割せよ35分
02. 総合 注文ウィジェット完成45分

総合 注文ウィジェット完成

師範 / 目安 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 の枠が現れ、点数と合計金額が読み取れる文を出す
  • 注文が空のときは、注文ボタンを押しても確認の枠を出さない

進め方

一息に書こうとすると必ず崩れます。順番があります。

  1. まず追加だけを作る。押したら行が増えて、品名が出るところまで
  2. 次に同じ品物を2回押したときに数量が増えるようにする
  3. 合計の計算を足す
  4. 数量の増減と、0での取り除きを作る
  5. 最後に確認画面を出す

1つ動くたびに画面で押して確かめて、次に進んでください。4番目までが本体で、5番目は問7で作ったものと同じ形です。

メニューのデータと見た目は用意してあります。書くのは App.jsx の中身だけです。

ヒントは3段階で、①方針、②使う構文、③部分解の順に出ます。1つも開けずに通せたら、その問題は自分のものです。


これで10問すべてです。陽葵さんが自分でメニューを3つ押し、数量を増やし、合計が跳ね上がるのを見て、注文ボタンを押しました。確認の枠が現れると、両手で頬をおさえて言いました。「商店街一、いただきました!」

師範が奥から一枚の紙を持って出てきます。そこには React道場・師範代を允許する と書かれていました。1つのカードを部品にするところから始めて、いまあなたは、state の置き場所を自分で決め、動く注文フローを白紙から組み上げられます。

ヒント

前のヒントを開くと次が開きます。開かずに解けると未開封クリアです

①方針 state に持つのは注文の配列1つだけにします。合計も点数も、その配列から描くたびに計算して出してください。追加のときは「もう入っているか」を先に調べ、入っていれば数量を増やす道、入っていなければ新しい行を足す道の2つに分けます。

ヒント 2ヒント 1 を開くと読めます
ヒント 3ヒント 2 を開くと読めます
App.jsx
styles.css
プレビュー

できているか

  • ブレンドを追加すると1行できて合計が480円になる
  • 同じ品物をもう一度追加すると行は増えず数量が2になる
  • 別の品物を足して減らすと、行が消えて合計も戻る
  • 数量を増やして注文すると、点数と合計の入った確認が出る
エディタを読み込んでいます