0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

非制御コンポーネントと制御コンポーネント、どれくらいパフォーマンス差がある?

0
Posted at

制御コンポーネントとは

React-wayな方法で入力の管理やフォームの値管理を行う。

例)useState()を使ってフォームの値を管理

非制御コンポーネントとは

制御コンポーネントでは無いもの。

例)useRef()を使ってフォームの値を管理

予想

制御コンポーネント(以下CC)では、stateでフォームの値を管理しているため、値が変わるたびにコンポーネントが再レンダリングされる。

一方非制御コンポーネント(以下UC)では、refで値を管理しており、値が変更されたとしてもコンポーネントの再レンダリングは行われない。

そのため、1つのコンポーネントが大量のフォームを持っている場合、CCでは再レンダリングのコストが高くなるため、パフォーマンスが落ちる。

UCでは再レンダリングが行われないため、フォームの数が増えてもパフォーマンスが悪化することはない。

検証

検証のために以下のコードを使いました。公開しているので、ぜひお手元で試してみてください。

Controlled.tsx
import { useEffect, useRef, useState } from "react";

export const Controlled = () => {
	// レンダリング時間計測用
	const startTimeRef = useRef<number>(0);

	const [formData, setFormData] = useState(
		Array(50)
			.fill("")
			.map(() => ({ name: "" }))
	);
	const handleFormDataChange = (formData: { name: string }[]) => {
		startTimeRef.current = performance.now();
		setFormData(formData);
	};

	// フォームとして成立させるために書いた
	// パフォーマンス比較としては不要
	const handleChange = (
		index: number,
		e: React.ChangeEvent<HTMLInputElement>
	) => {
		const { name, value } = e.target;
		const updatedFormData = [...formData];
		updatedFormData[index] = { ...updatedFormData[index], [name]: value };
		handleFormDataChange(updatedFormData);
	};

	// フォームとして成立させるために書いた
	// パフォーマンス比較としては不要
	const onSubmit = (e: React.FormEvent<HTMLFormElement>) => {
		e.preventDefault();
		console.log(formData);
	};

	// レンダリングされた時に呼ばれる
	useEffect(() => {
		console.log("制御コンポーネントがレンダリングされました");
	});

	// レンダリング時間計測用
	useEffect(() => {
		if (startTimeRef.current) {
			console.log(
				`制御コンポーネントのレンダリング時間: ${
					(performance.now() - startTimeRef.current) / 1000
				}秒`
			);
		}
		startTimeRef.current = 0;
	});

	return (
		<form onSubmit={onSubmit}>
			{formData.map((data, index) => (
				<div key={index}>
					<input
						name="name"
						value={data.name}
						onChange={(e) => handleChange(index, e)}
					/>
				</div>
			))}
			<input type="submit" />
		</form>
	);
};
UnControlled.tsx
import { useEffect, useRef } from "react";

export const UnControlled = () => {
	const formRef = useRef<HTMLFormElement>(null);

	// フォームとして成立させるために書いた
	// パフォーマンス比較としては不要
	const onSubmit = (e: React.FormEvent<HTMLFormElement>) => {
		e.preventDefault();
		const inputValue = (formRef.current?.elements[0] as HTMLInputElement).value;
		console.log(inputValue);
	};

	// レンダリングされた時に呼ばれる
	useEffect(() => {
		console.log("非制御コンポーネントがレンダリングされました");
	});

	return (
		<form ref={formRef} onSubmit={onSubmit}>
			{Array.from({ length: 50 }).map((_, index) => (
				<div key={index}>
					<input type="text" name="name" />
				</div>
			))}
			<input type="submit" />
		</form>
	);
};

こちらのコードで試してみたところ、CCではフォームの値を変更するたびに、0.01〜0.02秒かかっていることが確認できました。

一方UCでは、フォームの値を変更しても再レンダリングが起きていないことが確認できました。

結論

一定の条件下において、非制御コンポーネントの方がパフォーマンスが良くなるというのは事実であることが確認できました。ですが、1つのコンポーネントあたりのフォーム数が少ない場合、大きな違いはなくなりそうです。

結論、以下のように使い分けるのが良さそうだと感じました。

  • 制御コンポーネントを使う
    • 入力されている内容に対して、リアルタイムにバリデーションなどの検証を行いたいとき
  • 火制御コンポーネントを使う
    • 1つのコンポーネントに多数のフォームが存在するとき

参考

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?