この課題のねらい
この演習は「イベント処理 × useState」のセットに慣れることがテーマです。
つまり、
ボタンを押したら何かが変わる
入力欄に文字を打ったら state に反映される
その state を使って画面がリアルタイムに変わる
という「動く UI」の基本パターンを、自分の手で確認してもらいます。
必須課題① ボタン押下でメッセージ変更
イベントで state を変える流れ
まずは、「ボタンを押したらメッセージが変わる」シンプルな例からいきます。app/page.tsx に以下のようなコンポーネントを書いてみましょう。
"use client";
import { useState } from "react";
export default function MessageExample() {
const [message, setMessage] = useState("ボタンを押してみてください");
function handleClick() {
setMessage("ボタンが押されました!");
}
return (
<main style={{ padding: "24px", fontFamily: "sans-serif" }}>
<h1>イベント処理の基本</h1>
<p style={{ marginBottom: "12px" }}>{message}</p>
<button onClick={handleClick}>メッセージを変更</button>
</main>
);
}
TSXここでやっていることを分解します。
const [message, setMessage] = useState("ボタンを押してみてください");
このコンポーネントは message という状態を持ち、初期値は「ボタンを押してみてください」。
function handleClick() { setMessage("ボタンが押されました!"); }
ボタンが押されたときに呼ばれる関数。message を新しい文字列に更新します。
JSX の中で<p>{message}</p> として、現在の message を画面に表示。<button onClick={handleClick}> として、クリック時に handleClick を実行。
流れを文章にすると、
画面初期表示では「ボタンを押してみてください」が見える
ボタンを押すと handleClick が呼ばれる
setMessage によって message が更新される
React が再描画して、{message} の部分が「ボタンが押されました!」に変わる
「イベントで state を変える → state が UI を変える」という、React の基本パターンです。
必須課題② inputの値をstateに保存
入力欄を「stateの鏡」にする
次は、input の値を state に保存するパターンです。
React では、入力欄を「制御されたコンポーネント」として扱うのが基本でした。
"use client";
import { useState } from "react";
export default function InputExample() {
const [name, setName] = useState("");
function handleChange(e: React.ChangeEvent<HTMLInputElement>) {
setName(e.target.value);
}
return (
<main style={{ padding: "24px", fontFamily: "sans-serif" }}>
<h1>input と state</h1>
<input
type="text"
value={name}
onChange={handleChange}
placeholder="名前を入力してください"
style={{ padding: "8px", width: "240px" }}
/>
<p style={{ marginTop: "12px" }}>今の入力値: {name}</p>
</main>
);
}
TSXここで重要なのは 2 つです。
value={name}
入力欄に表示される文字は、常に state name によって決まる。
つまり「input は name の鏡」。
onChange={handleChange}
ユーザーが文字を打つたびに handleChange が呼ばれる。
handleChange の中では、
e.target.value で「今の入力欄の中身」を取り出し、それを setName に渡しています。
結果として、
入力 → onChange → setName で state 更新 → 再描画 → value={name} に反映
というループができあがります。
「input の中身を直接いじる」のではなく
「state を変えた結果が input に反映される」
という感覚が持てると、フォーム処理全体が理解しやすくなります。
挑戦課題 入力文字数をリアルタイム表示
stateから「導き出せる情報」を表示する
ここまできたら、入力文字数をリアルタイムに表示するのは難しくありません。
すでに name という state があるので、その .length を使えばよいだけです。
"use client";
import { useState } from "react";
export default function InputLengthExample() {
const [text, setText] = useState("");
function handleChange(e: React.ChangeEvent<HTMLInputElement>) {
setText(e.target.value);
}
const length = text.length;
return (
<main style={{ padding: "24px", fontFamily: "sans-serif" }}>
<h1>入力文字数カウンター</h1>
<input
type="text"
value={text}
onChange={handleChange}
placeholder="何か入力してください"
style={{ padding: "8px", width: "280px" }}
/>
<p style={{ marginTop: "12px" }}>今の入力値: {text}</p>
<p>文字数: {length}</p>
</main>
);
}
TSX重要なポイントは、「文字数を state にしない」ことです。
const length = text.length;
のように、「他の state から計算で求められる値」は、state にせずその場で計算するのが基本です。
理由は、
state にすると、「text を変えたのに length を更新し忘れた」のようなズレが起きる
計算で出せるものは毎回リアルタイムに求めたほうが一貫性が保てる
からです。
入力するたびに、
text が変わる
length も新しい text から計算される
画面上の「今の入力値」「文字数」が同時に更新される
という動きを自分の目で確認してみてください。
まとめ:イベント処理でつかんでほしい感覚
この演習で本当に身につけてほしいのは、次の流れです。
ボタンや input に「イベントハンドラ関数」を渡す(onClick / onChange)
イベントが発生すると、その関数の中で state を更新する(setXxx)
更新された state が JSX に反映されて、UI が変わる
この「イベント → state 更新 → UI 更新」が分かれば、
トグルボタン(ON/OFF)
フォームの入力チェック
フィルタリングボタン(押すと一覧が絞り込まれる)
など、実用的な UI にどんどん応用できます。
もし余力があれば、次のようなアレンジにも挑戦してみてください。
最大文字数を 20 にして、「20文字を超えたら赤文字で警告を出す」
入力が空のときは「まだ何も入力されていません」と表示する
