営業中バッジと時計
中段 / 目安 30分
陽葵さんがJS道場のときの画面を思い出しながら聞いてきます。「営業中バッジと時計、モダン化後も欲しい! Reactだとタイマーってどう扱うの?」。
ここで初めて useEffect を触ります。これまで書いてきたのは「state を受け取って画面を返す」だけの、外の世界と関わらない部品でした。ところがタイマーを動かす、通信する、といった処理は画面を返すのとは別の仕事です。こういう描画の外側で起こす処理を副作用と呼び、React では useEffect の中に置きます。
JavaScript (JSX)
useEffect(() => {
const id = setInterval(() => {
setTick((t) => t + 1);
}, 1000);
return () => clearInterval(id);
}, []);3つの部分に分かれています。中身が始めたい処理、return で返す関数が片付け、末尾の [] がいつ動かすかの指定です。
[] は「最初の1回だけ」を意味します。ここを書き忘れると、部品が描き直されるたびに新しいタイマーが増え、1秒に何十回も動く画面ができあがります。
そして return の片付けです。これを書かないと、部品が画面から消えたあともタイマーは回り続け、もう無い部品の state を触ろうとします。始めたものは自分で終わらせる、それが useEffect の作法です。書いておくと React が消えるときに呼んでくれます。
さて、時計そのものの判定について正直に言っておきます。「今の時刻を出す」コードは、実行するたびに答えが変わるので採点できません。だから今回は、JS道場の問8・問9と同じ手を使います。時刻を引数で受け取る形に切り出し、テスト用のボタンでいくつかの時刻を試すのです。
具体的には、時・分・秒を受け取って 09:05:03 の形に整える関数と、時を受け取って営業中かを返す関数の2つを作ってもらいます。これらは引数だけで答えが決まるので、何度動かしても同じ結果になり、確かめようがあります。時刻に依存する処理を、依存しない小さな関数として切り出すのは実務でもそのまま使う考え方です。
そのうえで useEffect と clearInterval は完成条件に残します。判定はできませんが、書く練習をしないと身につきません。片付けを書かなかった人がどうなるかは、師範いわくデバッグ道場の問6で分かるそうです。
完成条件
- 時・分・秒を受け取り
09:05:03のようにゼロ埋めして返す関数を作り、classNameがclockの要素に出す - 時を受け取り、7以上22未満なら営業中と判定する関数を作る
classNameがbadgeの要素に、営業中なら「営業中」とopenクラス、そうでなければ「準備中」とclosedクラスを付ける- 時刻ボタンを押すと、時計と バッジの両方がその時刻のものに変わる
useEffectの中でsetIntervalを始め、returnでclearIntervalして片付ける。依存配列は空にする
進め方
先に整形と営業判定の2つの関数を作り、ボタンで切り替わるところまで仕上げてください。そこが通れば問題の主要部は終わりです。useEffect は最後に足します。
ゼロ埋めは String(n).padStart(2, "0") が手軽です。
badge のクラスは className={"badge " + (open ? "open" : "closed")} のように組み立てます。badge を消してしまうと見た目が丸ごと崩れるので、必ず残したまま足してください。
ヒントは3段階で、①方針、②使う構文、③部分解の順に出ます。1つも開けずに通せたら、その問題は自分のものです。
ヒント
前のヒントを開くと次が開きます。開かずに解けると未開封クリアです