コース一覧
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分

いいねボタン

初段 / 目安 15分

カードが部品になって上機嫌の陽葵さんが、次の注文を出してきます。「メニューに『いいね』を付けたい。押すたび数字が増える、あの中毒性のやつ」。

画面にはすでにボタンと、いいね数を出す className="likes" の段落が置いてあります。押しても数字は 0 のまま動きません。初期コードは普通の変数でいいね数を持っているからです。

ここが React の最初の分かれ道です。普通の変数を書きかえても画面は変わりません。 変数の値は確かに増えますが、React には「画面を作り直して」という合図が届かないので、前に描いた文字がそのまま残ります。仮に何かの拍子に部品の関数がもう一度呼ばれたとしても、let count = 0; の行を最初から実行し直すので、増やした値は 0 に戻ってしまいます。

この2つをまとめて引き受けるのが state です。useState で持たせた値は、更新関数を通して変えると React が変化に気づいて部品を呼び直し、呼び直されても値は前の続きから始まります。

書き方は const [count, setCount] = useState(0); です。左の count が今の値、右の setCount が値を変える関数で、初期値をかっこの中に渡します。増やすときは count = count + 1 ではなく setCount(count + 1) です。この違いが「画面が動くかどうか」を分けています。

完成条件

  • いいね数を useState で持つ
  • className="likes" の段落に「いいね 0」のように現在の数を出す
  • ボタンを押すたびに、表示される数が1ずつ増える

進め方

useState は React から読み込んで使います。初期コードの先頭には import { useState } from "react"; がすでに書いてあります。

ボタンに処理を付けるのは onClick です。HTML の onclick と違って、渡すのは文字列ではなく 関数そのもの です。onClick={handleLike} のようにかっこを付けずに渡すか、onClick={() => setCount(count + 1)} のようにその場で関数を作って渡します。onClick={handleLike()} と書くと、描いた瞬間に1回実行されてしまうので気をつけてください。

コンソールに数字が出ているのに画面が変わらないときは、まだ普通の変数を触っています。React では画面に出したい値は必ず state にする、と覚えておくと迷いません。

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

ヒント

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

①方針 画面に出したい値は普通の変数ではなく state に持たせます。押されたときにやることは「今の数に1足したものを、更新関数に渡す」だけです。

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

できているか

  • はじめは「いいね 0」と表示されている
  • ボタンを1回押すと「いいね 1」になる
  • そこからさらに2回押すと「いいね 3」になる
エディタを読み込んでいます