👷

React.FCやめました

2022/07/25に公開

ファンタラクティブのエンジニアの 太田 です。
Reactのコンポーネント定義にReact.FCを使うのをやめたことについて書きます。

背景

ファンタラクティブでは最近までReactをあまり使っていませんでした。
Vue (とくにNuxt) で開発を行うことが多かったのですが、VueやNuxtのバージョンアップのコストなどを考慮しReactでの開発を積極的に始めました。
それまで社内でReactの知見がなかったので、設計や実装について様々な検討をし、コンポーネントを作成する際にReact.FCはいらないのでないかという結論に至りました。 (VFCも同様です)

なぜFCをやめたか

Genericsが使えない (使いづらい)

たとえばセレクトボックスの汎用コンポーネントを作成する際、選択値にgenericsを使いたいことがあります。

type SelectProps<T extends number | string> = {
  value: T
  label: ReactNode
  options: {
    key: T
    label: ReactNode
  }[]
  onChange: (value: T) => void
}

FCを使用しなければ以下のように容易に使えますが、FCを使用した場合は簡単にはできません。
いろいろ調べましたがFCでGenericsを使うには複雑な呪文のようなコードを書かなければいけません。 (それでもうまく使えるかはわかりません)

const Select = <T extends number | string>({}: SelectProps<T>) => {}
<Select<string> />

FCを使うメリットは何か

FCの定義

type FC<P = {}> = FunctionComponent<P>;
interface FunctionComponent<P = {}> {
  (props: PropsWithChildren<P>, context?: any): ReactElement<any, any> | null;
  propTypes?: WeakValidationMap<P> | undefined;
  contextTypes?: ValidationMap<any> | undefined;
  defaultProps?: Partial<P> | undefined;
  displayName?: string | undefined;
}

なさそう。
しいていうならFunctionalComponentということがわかりやすくなるくらい。
しかしreact hooksが登場した現在、FunctionalComponentと明示的にわかるようにすることの価値も薄れているように感じます。
propTypesやcontextTypesはFCを使わなくても容易に定義できます。
defaultPropsも以下のように定義できます。

const Select = <T extends string | number> = ({
  value = '' // デフォルト値
}) => {}

propsにchildrenを自動的に含めるようにしてくれますが正直余計なお世話です。

まとめ

React.FC (VFCも) を使うことによるデメリットはあるけどメリットは感じられなかったため使用することをやめました。
React.FCを使うことによるメリットがあれば教えてほしいです。

ファンタラクティブテックブログ

Discussion