【React】制御コンポーネントと非制御コンポーネント

ReactのFormライブラリに触れる中で「(非) 制御コンポーネント」というワードをよく目にするが、正直定義がよく分かっていなかったので調べた。

結論

  • 制御コンポーネント:入力値をReactコンポーネントが保持する
  • 非制御コンポーネント:入力値をDOMが保持する

制御コンポーネント

import { type ChangeEvent, useState } from 'react';
export default function ControlledComponent() {
const [inputValue, setInputValue] = useState<string>('');
const handleChange = (e: ChangeEvent<HTMLInputElement>) => {
setInputValue(e.target.value);
};
const handleSubmit = () => {
// some logic
alert(inputValue);
};
return (
<form onSubmit={handleSubmit}>
<input type="text" value={inputValue} onChange={handleChange} />
<button type="submit">submit</button>
</form>
);
}
  • テキストボックスへの入力値をstateとして保持し、change時はstateを更新。submit時はそのstateを参照する。
  • リアクティブな実装に向いている
    • 入力する度に実行するバリデーション
    • ボタンのdisabledの制御
  • 入力項目が増えた時のstateの管理が大変になる
  • 入力する度に再レンダリングされてしまう

非制御コンポーネント

import { useRef } from 'react';
export default function UncontrolledComponent() {
const inputRef = useRef<HTMLInputElement | null>(null);
const handleSubmit = () => {
// some logic
alert(inputRef.current?.value);
};
return (
<form onSubmit={handleSubmit}>
<input type="text" ref={inputRef} />
<button type="submit">submit</button>
</form>
);
}
  • refを対象DOMに設定し、入力値をそのDOMから参照する
  • stateの更新による再レンダリングが発生しない
  • 1回限りの値の取得に向いている
    • 送信時のバリデーション
  • 「入力するたびに〜」といった処理には向いていない

1

参考
  1. Controlled and uncontrolled form inputs in React don’t have to be complicated

動画でより詳しく話しています