React.FCとは何かの整理
はじめに
ChatGPTでReactのコーディングをしている際に、
import React from 'react';
interface Props {
...
}
const Component: React.FC<Props> = ({...}) => {
return (
<>
...
</>
);
};
みたいな記述がたまに見られ、気になったので調べることにしました。
React.FCとは
React.FC(Function Component)は、ジェネリクス型と呼ばれるものです。
※ジェネリクス型:型も変数のように扱えるようにしたもの
React.FCでは、関数コンポーネントが受け取るpropsを指定できるという特徴があります。
React.FCのメリット
- コンポーネントが受け取るpropsに対して型安全性を提供できる。
開発者が意図したデータ型のみを扱い、型エラーのコンパイルがしやすくなります。
これにより、バグの早期発見に役立ち、コードの理解もしやすくなるというメリットがあります。
例:propsに型をつけない場合
const Greeting = ({ name }) => {
return <h1>Hello, {name.toUpperCase()}</h1>;
};
// 呼び出し側
<Greeting name={123} /> // ← 数字を渡してもエラーにならない
この場合、実行時に123.toUpperCase()が呼び出されてエラーが発生する。
(JavaScriptだと実行するまでエラーが分からない)
例:propsに型をつけた場合(React.FCでもprops型直書きでもOK)
type GreetingProps = { name: string };
const Greeting: React.FC<GreetingProps> = ({ name }) => {
return <h1>Hello, {name.toUpperCase()}</h1>;
};
// 呼び出し側
<Greeting name={123} /> // ❌ TypeScript がコンパイルエラーを出す
<Greeting name="Alice" /> // ✅ これは問題なく通る
型を明示的にすることで、間違った型を渡した瞬間にエラーが出るため、実行前にエラーに気づくことができます。これにより、
- バグの早期発見
- props型の可視化によるコード理解
といった恩恵を受けることができます。
- コンポーネントのpropsのリファクタリングがしやすい。
例えば、あるpropsの名前を変更したくなったとします。
この場合、TypeScriptのコンパイラがそのpropsを使用している箇所を検出してくれるので、リファクタリングがしやすくなります。
たとえば、下記の例を考えてみます。
変更前
type GreetingProps = { name: string };
const Greeting: React.FC<GreetingProps> = ({ name }) => (
<h1>Hello, {name}</h1>
);
// 呼び出し側
<Greeting name="Alice" />
<Greeting name="Bob" />
このnameというpropsを、userNameにリファクタリングしたくなったとします。
変更後
type GreetingProps = { userName: string };
const Greeting: React.FC<GreetingProps> = ({ userName }) => (
<h1>Hello, {userName}</h1>
);
変更後では、変更前の呼び出し例はすべてエラーとして検出されます。
<Greeting name="Alice" /> // ❌ name はもう存在しない
<Greeting name="Bob" /> // ❌
このように、TypeScriptが「この呼び出しは間違っているよ」と全部自動で検出してくれるので、
呼び出すpropsを安心して一括置換することができます。
もし、この機能がなかったら、プロジェクト内のname=をctrl+Fとかでgrepしながら手直しする必要があるため、そこで人為的なミスが生じる可能性が出てしまいます。
- 型定義を見るだけで、そのコンポーネントがどのようなpropsを想定しているか分かりやすい
React.FCを使って下記のようなコードを書いたとします。
type GreetingProps = {
name: string;
};
const Greeting: React.FC<GreetingProps> = ({ name, children }) => (
<div>
<h1>Hello, {name}</h1>
{children}
</div>
);
この場合、このコードを見た人は
-
Greetingコンポーネントは、name:stringを必須で受け取る -
childrenも受け取ることができる
という2つの情報が形定義を見るだけで分かるようになります。
最近のReact(19)では使わない書き方が主流?
React18より前のバージョンでは、React.FCに暗黙的にchildrenが含まれていたようです。
ところが、React18からは暗黙的にchildrenが含まれなくなったみたいです。
自分は個人的に学習をしているため、React.FCをどう使うか?と言った細かい部分までは突き詰めていませんでした。
ですが、チーム単位でReactのWebアプリケーション開発などを進めていく場合は、チーム内の方針などによって使い方が変わってくるかと思います。
参考
・https://dev.to/elhamnajeebullah/react-typescript-what-is-reactfc-and-why-should-i-use-it-4029
・https://typescriptbook.jp/reference/generics
Discussion