はじめに
「リセットボタンを押したのに、なぜかチェックボックスだけ元の状態のままで変わらない…」
こんな経験はありませんか?Reactでフォームを実装していると、一見すべてのフォーム要素をリセットしたはずなのに、なぜかチェックボックスだけが頑固に元の状態を維持している…という状況に遭遇することがあります。
今回は、この「チェックボックスだけリセットされない問題」の原因と、シンプルな解決策について解説します。その鍵は、defaultChecked
とchecked
プロパティの違いにあります。
問題の再現:チェックボックスだけがリセットされない...
まず、問題が発生するシンプルな例を見てみましょう
import React, { useState } from 'react';
function ProblemForm() {
const [name, setName] = useState('');
const [isAgree, setIsAgree] = useState(false);
const handleReset = () => {
setName('');
setIsAgree(false);
// ここでフォームをリセットしているつもり...
};
return (
<form>
<div>
<label>名前:</label>
<input
type="text"
value={name}
onChange={(e) => setName(e.target.value)}
/>
</div>
<div>
<label>
<input
type="checkbox"
defaultChecked={isAgree}
onChange={(e) => setIsAgree(e.target.checked)}
/> 利用規約に同意する
</label>
</div>
<button type="button" onClick={handleReset}>
リセット
</button>
</form>
);
}
このコードでは、リセットボタンをクリックすると次のことが起きます:
-
setName('')
で名前フィールドは空になります(UIも更新される) -
setIsAgree(false)
でチェックボックスの状態は内部的にfalse
になります - しかし、チェックボックスのUI上の表示は変わりません!
これはdefaultChecked
プロパティの性質によるものです。
defaultCheckedとcheckedの本質的な違い
defaultChecked
defaultChecked
は、その名前が示す通り「デフォルト(初期)値のみを設定する」ためのプロパティです。
- コンポーネントが最初にレンダリングされるときだけ適用される
- 一度レンダリングされたら、ステートが変わっても再評価されない
- HTMLの
defaultChecked
と同様の挙動をする
checked
一方、checked
は「現在の値」を表すプロパティです。
- 常に現在の状態を反映する
- 値が変わるたびに再評価され、UIも更新される
- ReactによるUIの制御を可能にする
解決策:defaultCheckedからcheckedへの変更
問題を解決するには、defaultChecked
をchecked
に変更するだけです:
import React, { useState } from 'react';
function FixedForm() {
const [name, setName] = useState('');
const [isAgree, setIsAgree] = useState(false);
const handleReset = () => {
setName('');
setIsAgree(false);
};
return (
<form>
<div>
<label>名前:</label>
<input
type="text"
value={name}
onChange={(e) => setName(e.target.value)}
/>
</div>
<div>
<label>
<input
type="checkbox"
checked={isAgree} {/* defaultCheckedからcheckedに変更 */}
onChange={(e) => setIsAgree(e.target.checked)}
/> 利用規約に同意する
</label>
</div>
<button type="button" onClick={handleReset}>
リセット
</button>
</form>
);
}
この変更により:
-
setIsAgree(false)
が実行されると、isAgree
ステートがfalse
に更新される -
checked={isAgree}
は新しい値false
を反映する - チェックボックスのUI状態も正しく更新される
いつdefaultCheckedを使い、いつcheckedを使うべきか?
defaultCheckedの使いどころ
- フォームのリセットやプログラムによる変更が不要な場合
- ユーザー入力のみでチェックボックスを制御する場合
- 初期値のみを設定して、あとはユーザーに委ねる場合
checkedの使いどころ
- フォームのリセット機能がある場合(今回のケース)
- プログラムによる状態変更が必要な場合
- 他のUI要素と連動して状態を変更する場合
チェックボックスのリセット問題をチェックするポイント
フォームのリセット機能を実装する際は、以下のポイントを確認しましょう:
- チェックボックスには
defaultChecked
ではなくchecked
を使用しているか - ステートの更新とUI表示が連動しているか
- 全てのフォーム要素で統一した制御方法(制御コンポーネント)を使用しているか
まとめ
Reactでフォームを実装する際、チェックボックスだけがリセットされない問題はdefaultChecked
とchecked
の違いを理解することで簡単に解決できます。
-
defaultChecked
:初期レンダリング時のみ評価される -
checked
:常に現在の値を反映し、値が変わるとUIも更新される
プログラムによってチェックボックスの状態を変更する必要がある場合(フォームリセットなど)は、必ずchecked
プロパティを使用しましょう。これにより、内部状態とUI表示の同期が保たれ、ユーザーに一貫した体験を提供できます。
次回フォームを実装するときは、チェックボックスにdefaultChecked
とchecked
のどちらを使うべきか、意識して選択してみてください。