VFCを使うべきか、FCを使うべきか、それとも不要かを整理していきたいと思います。
- react 18.2.0
VFC・FCとは?
Functional Componentの型のことです。
FCだとこんな感じで定義してあり、戻り値の指定といくつかのフィールドを持っています。
type FC<P = {}> = FunctionComponent<P>;
interface FunctionComponent<P = {}> {
(props: P, context?: any): ReactElement<any, any> | null;
propTypes?: WeakValidationMap<P> | undefined;
contextTypes?: ValidationMap<any> | undefined;
defaultProps?: Partial<P> | undefined;
displayName?: string | undefined;
}
FCの昔(v18以前)
FCはchildren
が定義してあったので、childrenが不要なコンポーネントにchildrenを渡してもエラーが出ないという問題点がありました。
TypeScriptで型の抜け道は良くないですよね。
interface Props {
name: string;
}
const SomeComponent: React.FC<Props> = ({ name }) => (
<p>{name}</p>;
);
const ParentComponent: React.FC = () => (
<SomeComponent name="sam">
children
</Component>
);
VFCの登場
そこで、VFCという型が登場しました。
VFCにはchildren
が存在していないので定義していない場合にはエラーが表示されました。
ERROR: Type '{ children: string; name: string; }' is not assignable to type...
interface Props {
name: string;
}
const SomeComponent: React.VFC<Props> = ({ name }) => (
<p>{name}</p>;
);
const ParentComponent: React.VFC = () => (
<SomeComponent name="sam">
children
</Component>
);
childrenを渡すには明示的に定義すれば渡すことができます。
interface Props {
name: string;
children: React.ReactNode;
}
const SomeComponent: React.VFC<Props> = ({ name, children }) => (
<div>
<p>{name}</p>;
<p>{children}</p>;
</div>
);
const ParentComponent: React.VFC = () => (
<SomeComponent name="sam">
children
</Component>
);
モグモグさん
追加された実際のPRはこちらです。
現在のVFCとFC
というわけで、v18より前はVFCは結構使われていましたが、v18からはFCからchildrenが除かれました。
つまり、FCとVFCは同じ型になったということです。
それによって、VFCはdeprecatedになりました。
// React.FunctionComponent
type FC<P = {}> = FunctionComponent<P>;
interface FunctionComponent<P = {}> {
(props: P, context?: any): ReactElement<any, any> | null;
propTypes?: WeakValidationMap<P> | undefined;
contextTypes?: ValidationMap<any> | undefined;
defaultProps?: Partial<P> | undefined;
displayName?: string | undefined;
}
// @deprecated - Equivalent with `React.FC`.
type VFC<P = {}> = VoidFunctionComponent<P>;
interface VoidFunctionComponent<P = {}> {
(props: P, context?: any): ReactElement<any, any> | null;
propTypes?: WeakValidationMap<P> | undefined;
contextTypes?: ValidationMap<any> | undefined;
defaultProps?: Partial<P> | undefined;
displayName?: string | undefined;
}
モグモグさん
結論: 現在はVFCではなくFCを使うことが推奨されています。
FCは使うべき?
VFCは使わなくなったわけですが、そもそもFCを使うべきなのかどうなのか。
JSX.Element
との違いは、null
を返せるか定義されたフィールドがあるかどうかの違いです。
namespace JSX {
interface Element extends React.ReactElement<any, any> { }
propTypes
やdefaultProps
は使わなそうですが、displayNameはプロジェクトによっては使います。
モグモグさん
結論: プロジェクトの性質や書き方、個人やチームの方針で決めるでいいかなと思いました。
ただ「一応使っておこう」の場合は当てはまるかはわからないですが、YAGNI原則に則って不要なんじゃないかなと思っております。
FCに変更が入れば対応するコストもかかる可能性も増えますよね。
まとめ
VFCを使うべきか、FCを使うべきか、それとも不要かを整理しました。
v18からはVFCは非推奨で使うべきではないです。
FCを使うか使わないかは違いを理解して、プロジェクトの性質や書き方、個人やチームの方針で決めるのがいいのではと個人的には思っています。
VFCとFCでちょっと混乱している方に役に立てば幸いです。