markdown
はじめに (対象読者・この記事でわかること)
この記事は、React を使って Web フロントエンド開発を行っている方、特に「input type=\"text\" の値をボタン操作でリセットしたい」と考えている初心者〜中級者を対象としています。
この記事を読むことで、以下のことができるようになります。
- Controlled Component と Uncontrolled Component の違いを理解し、適切に選択できる
useStateやuseRefを用いたシンプルなリセット実装方法をマスターできる- 余計な再レンダリングを防ぎつつ、フォームのクリア処理を安全に組み込める
React 開発で頻繁に出くわす「入力欄を初期化したい」シナリオにすぐに適用できる実装例と、実装時にハマりやすいポイントの対策も併せて紹介します。
前提知識
この記事を読み進める上で、以下の知識があるとスムーズです。
- HTML と CSS の基本的な知識
- JavaScript(ES6 以降)の構文に慣れていること
- React(関数コンポーネント、フック)の基礎的な理解
入力リセットの必要性と基本的考え方
Web アプリケーションでは、ユーザーが入力したテキストを クリア したいケースが多々あります。たとえば、検索フィールドの「リセット」ボタン、コメント投稿後の入力欄の消去、または「新規作成」画面での全項目初期化などです。
React では Controlled Component と Uncontrolled Component の二つのアプローチがあり、実装方法が大きく分かれます。
- Controlled Component は
valueプロパティを状態 (state) と完全に同期させ、状態が変わるたびに再レンダリングが走ります。リセットは状態を空文字に戻すだけで完了しますが、状態管理が増える点に注意が必要です。 - Uncontrolled Component は DOM の内部状態を直接操作し、React 側では
refで要素を参照します。リセットはref.current.value = ''と書くだけで済み、状態管理が減りますが、値取得時にref経由になるためコードがやや散らかりやすいです。
どちらの方法も アクセシビリティ(フォーカス制御や ARIA 属性)を考慮すれば、ユーザー体験を損なわずに実装できます。次の章では、具体的なコード例と共に両アプローチの実装手順を詳しく解説します。
実装方法詳細とサンプルコード
この章では、実際に「テキスト入力をボタンでリセットする」機能を実装する手順を ステップ別 に示します。まずは Controlled Component での実装、続いて Uncontrolled Component での実装を行い、最後にハマりやすいポイントとその解決策をまとめます。
ステップ 1:プロジェクトのセットアップ
Bash# npm または yarn で React プロジェクトを作成 npx create-react-app input-reset-demo cd input-reset-demo npm start
src/App.js を開き、以下のようにシンプルなコンポーネントを作成します。ここでは Controlled と Uncontrolled の二つのバージョンを同時に表示させ、比較しやすくしています。
Jsximport React, { useState, useRef } from "react"; function ControlledInput() { const [text, setText] = useState(""); const handleReset = () => setText(""); return ( <div style={{ marginBottom: "1rem" }}> <h3>Controlled Input</h3> <input type="text" value={text} onChange={(e) => setText(e.target.value)} placeholder="ここに入力" /> <button onClick={handleReset}>リセット</button> </div> ); }
ステップ 2:Uncontrolled コンポーネントの実装
次に、useRef を使って DOM 要素へ直接アクセスする方式です。
Jsxfunction UncontrolledInput() { const inputRef = useRef(null); const handleReset = () => { if (inputRef.current) { inputRef.current.value = ""; // 必要ならフォーカスも戻す inputRef.current.focus(); } }; return ( <div> <h3>Uncontrolled Input</h3> <input type="text" ref={inputRef} placeholder="ここに入力" /> <button onClick={handleReset}>リセット</button> </div> ); }
ステップ 3:全体を組み合わせる
Jsxexport default function App() { return ( <div style={{ padding: "2rem", fontFamily: "Arial, sans-serif" }}> <h2>React で input をボタンでリセットするデモ</h2> <ControlledInput /> <UncontrolledInput /> </div> ); }
これで起動しているアプリ上に、Controlled と Uncontrolled の2つの入力欄が表示され、各「リセット」ボタンをクリックすると即座にテキストがクリアされます。
ハマった点やエラー解決
| 発生した問題 | 原因 | 解決策 |
|---|---|---|
| ボタンを押しても値が消えない | value を状態と結びつけ忘れた(Controlled の場合) |
setText('') を正しく呼び出す |
inputRef.current が null になる |
コンポーネントがマウントされる前にリセット関数が走った | handleReset をボタンの onClick にだけ紐付け、早期呼び出しを防止 |
| 再レンダリングが多くなりパフォーマンスが低下 | 大量の入力欄を Controlled で管理していた | 必要に応じて Uncontrolled に切り替えるか、React.memo で子コンポーネントをメモ化 |
| リセット後にフォーカスが外れる | setState 後に自動的に再レンダーが走り、ブラウザのデフォルト挙動が発動 |
Uncontrolled の場合は focus() を明示的に呼び、Controlled の場合は useEffect で ref を使用 |
さらに洗練させるテクニック
- カスタムフック
useInputResetを作成すると、複数箇所で同じロジックを再利用できる。 - フォーム全体のリセット では、
react-hook-formのreset()メソッドを活用すると、バリデーション状態まで一括クリアできる。 - アクセシビリティ を考慮し、リセットボタンに
aria-label="入力欄をクリア"を付与するとスクリーンリーダー利用者にも配慮できる。
まとめ
本記事では、React でテキスト入力を ボタン一つでリセット する方法を、Controlled と Uncontrolled の二つの視点から解説しました。
- Controlled:
useStateで値を管理し、setState('')で即座にリセット - Uncontrolled:
useRef経由で DOM のvalueを直接書き換える - 実装時に陥りやすい「null 参照」や「再レンダリング過多」などの問題と、具体的な解決策を提示
これらの知識を活かすことで、フォームのクリア処理を安全かつ効率的に実装でき、ユーザー体験の向上につながります。次回は、react-hook-form と組み合わせた高度なバリデーション・リセットパターンについて解説する予定です。
参考資料
- React 公式ドキュメント – Forms
- React Hooks – useRef
- WAI‑ARIA Authoring Practices – Keyboard Interaction for Form Controls