LESSON 06 · 約30分
フォームの入力を、状態につなぐ
ラベル付きの入力と送信を作り、空欄・エラー・結果の状態を扱います。
コードを試す前に
01のVite reactテンプレート(JavaScript/JSX)を使います。特記のないApp.jsxは、そのレッスンだけで動く独立した例です。例同士を連結しないでください。
短い学習用の例です。各App.jsxは独立した例で、順に追記して一つの完成品にする形式ではありません。ファイル名、依存関係、未定義部分の前提は注記に記載します。問題内の抜粋や空欄は、そのまま実行するための完成コードではありません。
開発環境の準備を確認する →このレッスンでわかること
- controlled inputのvalueとonChangeを組み合わせられる
- フォームの送信と入力検証を実装できる
入力の値を誰が持つか
value={title}とonChangeでstateを更新する入力はcontrolled inputです。Reactのstateが表示値の基準になります。文字入力は空文字で初期化し、途中からundefinedに切り替えません。チェックボックスはvalueではなくcheckedとevent.target.checkedを組み合わせます。
送信はformで受ける
formのonSubmitなら、送信ボタンと入力中のEnterを同じ処理にできます。このローカル演習ではpreventDefaultで通常のページ移動を止め、trim後の空欄を検証します。入力中の値と、送信後の結果を別にすると、編集中なのか確定済みなのかが伝わります。
ラベルとエラーも画面の一部
placeholderだけをラベルの代わりにしません。labelのhtmlForとinputのidを対応させます。エラーがある場合は文章で理由を示し、aria-describedbyで関連付けます。実際にサーバーへ送るアプリでは、ブラウザーでの検証に加えてサーバー側でも入力と権限を検証します。
学習テーマを受け付ける
import { useState } from 'react';
export default function App() {
const [title, setTitle] = useState('');
const [error, setError] = useState('');
const [result, setResult] = useState('');
function handleSubmit(event) {
event.preventDefault();
const value = title.trim();
if (!value) {
setError('学習テーマを入力してください。');
setResult('');
return;
}
setError('');
setResult(`「${value}」を練習します。`);
setTitle('');
}
return (
<main>
<h1>テーマを決める</h1>
<form onSubmit={handleSubmit} noValidate>
<label htmlFor="topic">学習テーマ</label>
<input id="topic" value={title}
onChange={event => { setTitle(event.target.value); setError(''); }}
aria-invalid={Boolean(error)}
aria-describedby={error ? 'topic-error' : undefined} />
{error && <p id="topic-error" role="alert">{error}</p>}
<button type="submit">決定する</button>
</form>
<p role="status">{result}</p>
</main>
);
}noValidateはこの例で独自の検証メッセージを学ぶためです。IDはAppが1つだけ表示される前提。送信は端末内の状態更新だけで、通信や永続保存はしません。
TRY IT YOURSELF
入力と送信を確かめる
- 空文字とスペースだけの入力を送信し、理由が出るか確かめる
- 正しいテーマをEnterで送信し、結果と入力欄のリセットを確認する
- 20文字以内という条件を追加し、入力欄の近くへ条件を表示する
- マウスを使わずTab・文字入力・Enterで一連の操作を試す
できたらOK:空欄を受け付けず、ラベル付き入力をEnterで送信でき、成功とエラーが区別できる
QUICK CHECK
理解を確かめよう
公式資料でもう少し詳しく
ここまで読めたら、ひとつ前進。