React で checkbox の状態を別のところにある label で制御していて warning が出ていた
const Component = () => { const [isActive, setIsActive] = useState<boolean>(true); const handleOnActive = () => setIsActive(true); const handleDeActive = () => setIsActive(false); return ( <div> <input id="myCheckbox" type="checkbox" checked={isActive} /> <div className="tab"> <label htmlFor="myCheckbox" onClick={handleOnActive}>Tab 1</label> <label htmlFor="myCheckbox" onClick={handleDeActive}>Tab 2</label> </div> <div className="tabContent"> <div className={`content1 ${isActive ? 'show' : 'hide'}`} aria-hidden={!isActive}>content 1</div> <div className={`content2 ${isActive ? 'hide' : 'show'}`} aria-hidden={isActive}>content 2</div> </div> </div> ); };
You provided a `checked` prop to a form field without an `onChange` handler. This will render a read-only field. If the field should be mutable use `defaultChecked`. Otherwise, set either `onChange` or `readOnly`.
環境
- React
18.2.0
- TypeScript
5.2.2
Controlled Component には onChange
か readOnly
が必要
value や checked という状態を state 制御している Controlled Components は直接 state を変更できる onChange
を付けるか別のところで state を変更する場合は readOnly
にしておく必要がある
今回のケースだと label のクリックで checkbox の cheked (状態) を変更したいので readOnly
を付ける必要があった
const Component = () => { const [isActive, setIsActive] = useState<boolean>(true); const handleOnActive = () => setIsActive(true); const handleDeActive = () => setIsActive(false); return ( <div> - <input id="myCheckbox" type="checkbox" checked={isActive} /> + <input id="myCheckbox" type="checkbox" checked={isActive} readOnly /> <div className="tab"> <label htmlFor="myCheckbox" onClick={handleOnActive}>Tab 1</label> <label htmlFor="myCheckbox" onClick={handleDeActive}>Tab 2</label> </div> {/* 略 */} </div> ); };
Checkbox / Radio の checked
と defaultChecked
- checkbox / radio のチェック状態は
value
ではなくchecked
で管理する。(デフォルト値はdefaultValue
でなくdefaultChecked
を使う) checked
とdefaultChecked
は同時には使えない- 同時に使用すると warning が発生する
Component contains an input of type checkbox with both checked and defaultChecked props. Input elements must be either controlled or uncontrolled (specify either the checked prop, or the defaultChecked prop, but not both). Decide between using a controlled or uncontrolled input element and remove one of these props.
checked
がある場合はチェックの状態は state で制御されるのでデフォルト値を設定する必要がない- チェック状態を state で制御しない 非制御コンポーネント (
Uncontrolled Components
) として扱う場合はdefaultChecked
のみを使う
- 同時に使用すると warning が発生する
先のコンポーネントの check 状態を通常の HTML のように for
を使った label で変更させるだけであれば defaultChecked
を使った非制御コンポーネントにすることもできる
const UnControlledComponent = () => { return ( <div> <input id="myCheckbox" type="checkbox" defaultChecked={true} /> <div className="tab"> <label htmlFor="myCheckbox">Tab 1</label> <label htmlFor="myCheckbox">Tab 2</label> </div> <div className="tabContent"> {/* state を使わないので表示の切り替えは CSS で行う */} <div className="content1">content 1</div> <div className="content2">content 2</div> </div> </div> ); };
まとめ
- Radiobox / Radio のコンポーネントで state を使う必要があるのかどうかで Controlled Components にするか Uncontrolled Components を決める
- Uncontrolled Components なら
defaultChecked
を使う - Controlled Components なら
checked
で状態を state で扱う- 直接変更するには
onClick
を渡して state を変更できるようにする - label など別の要素から state を変更する場合は Checkbox / Radio には
readOnly
を付ける
- 直接変更するには
[参考]