はじめに
Reactのフォーム実装に関する「制御コンポーネント」と「非制御コンポーネント」についてまとめます。
制御コンポーネント
制御コンポーネントとは、フォームの入力値をReactコンポーネント(state)で扱うコンポーネントのことです。
メリットとしては、常に値にアクセスできるため、 ユーザが入力中にバリデーションを実施する 、といったリアクティブなフォームを作成できます。
デメリットとしては、入力値が更新されるたびに 再レンダリングが発生します。
制御コンポーネントの実装例
import { useState } from "react";
export const Controlled = () => {
const [inputValue, setInputValue] = useState<string>("");
const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
const value = e.target.value;
// 入力中にもバリデーション
if (value.length <= 10) {
console.log("10文字以上で入力してください");
}
setInputValue(value);
};
const handleSubmitClick = () => {
if (inputValue.length <= 10) {
return;
}
console.log(inputValue);
};
return (
<>
<p>制御コンポーネント</p>
<input type="text" value={inputValue} onChange={handleChange} />
<button onClick={handleSubmitClick}>送信</button>
</>
);
};
非制御コンポーネントとは
非制御コンポーネントとは、フォームの入力値をDOMで扱うコンポーネントのことです。
useRef
とinput要素のref
属性を使用します。
メリットとしては、stateを経由しないため、入力値の更新毎に 再レンダリングが発生しません。
デメリットとしては、必要なタイミング(submit時など)でDOMから入力値を取得するため、入力中にバリデーションを実施する、といった実装が難しいことが挙げられます。
非制御コンポーネントの実装例
import { useRef } from "react";
export const Uncontrolled = () => {
const ref = useRef<HTMLInputElement>(null);
const handleSubmitClick = () => {
const value = ref.current?.value;
// submit時にバリデーション
if (value && value.length <= 10) {
console.log("10文字以上で入力してください");
return;
}
console.log(value);
};
return (
<>
<p>非制御コンポーネント</p>
<input type="text" ref={ref} />
<button onClick={handleSubmitClick}>送信</button>
</>
);
};
両者の比較とReact Hook Form
React公式では制御コンポーネントの使用を推奨しています。
理由としてはメリットで挙げた「入力中のバリデーション」など、できることが多いためです。
ただ、パフォーマンスへの懸念を考えると非制御コンポーネントを使いたくなるかと思います。
このような場合、React Hook Formを使うことで両者のメリットを享受できます。
React Hook Formは非制御コンポーネントを採用しており、ref
属性にregister
を渡すことで、フォームの実装ができます。
基本的な使い方を以下の記事にまとめました。
React Hook FormとZodの基本的な使い方
また、なぜ非制御コンポーネントであるにも関わらず、リアクティブなフォームを実装できるのか?という疑問が出てくるかと思います。
これについては以下の記事に詳細にまとめられていたため、引用させていただきます。
React Hook Formは非制御コンポーネントからどうやって変更を検知しているのか
参考記事
採用のお知らせ
株式会社Relicでは、エンジニア・デザイナーを積極的に採用中です。
またRelicでは、地方拠点がありますので、U・Iターンも大歓迎です!🙌
少しでもご興味がある方は、Relic採用サイトからエントリーください!