WebLog

コンポーネントに型をつけるときFCを使うかJSX.Elementを使うか

2022/12/15 19:45

最初に

この記事は qiita から移行したものです。

この記事を書く動機

メモ 間違っている部分があればコメントで教えてください。

前提知識

【検証】React.FC と React.VFC はべつに使わなくていい説 – KRAY Inc.

【検証】React.FC と React.VFC はべつに使わなくていい説 – KRAY Inc.

アジャイルソフトウェア開発を採用し、HTML5やRuby on Railsでマルチデバイス環境で動くWebアプリケーションやWebサービスの開発が得意な会社です。

GitHub - typescript-cheatsheets/react: Cheatsheets for experienced React developers getting started with TypeScript
GitHub - typescript-cheatsheets/react: Cheatsheets for experienced React developers getting started with TypeScript

GitHub - typescript-cheatsheets/react: Cheatsheets for experienced React developers getting started with TypeScript

Cheatsheets for experienced React developers getting started with TypeScript - GitHub - typescript-cheatsheets/react: Cheatsheets for experienced React developers getting started with TypeScript

問題

以下、尊敬するエンジニアの方々のツイートを引用させていただきました(いつもツイートから勉強させてもらっています。ありがとうございます!):

自分はReact.FCを使い続ける派だな。関数の返り値は推論させるより明示したほうが有利という前提はまずあり、 引数と返り値の2箇所の型注釈を書くより変数に型注釈一発のほうが見やすいという個人的嗜好があるので(?)

大岡由佳『りあクト! 第4版』BOOTHで販売中!紙本も
大岡由佳『りあクト! 第4版』BOOTHで販売中!紙本も
@oukayuka

React 限定の話題ですが、18から関数コンポーネントの型 React.FC の props から暗黙の children が除外されました。React+TypeScript Cheatsheets という☆33kのドキュメントでは、FC を使うのをやめて children: ReactNode を props の型に明記することを推奨しています。 github.com/typescript-che…

36
Reply

これまでの経緯を振り返る

React v17 までの書き方

  • FC と VFC を使い分ける方法 基本は VFC を使い、children が props に必要なものだけ FC を使う:
1// 普通のコンポーネントにはVFCを使う
2export const Button: VFC<{ text: string }> = ({ text }) => {
3 return <button>{text}</button>;
4};
5
6// ラッパーコンポーネントなどchildrenが必要なものだけFCを使う:
7export const Layout: FC = ({ children }) => {
8 return (
9 <>
10 <Header />
11 {children}
12 <Footer />
13 </>
14 );
15};

もしくは VFC だけを使い、children が必要なときは明示的に props に書く:

1export const Layout: VFC<{ children: ReactNode }> = ({ children }) => {
2 return (
3 <>
4 <Header />
5 {children}
6 <Footer />
7 </>
8 );
9};
  • JSX.Element を使う方法(v18 でも変更なし)
1// propsの型の宣言
2type AppProps = {
3 message: string;
4};
5
6// Function Componentの最も簡単な宣言方法です。返り値の型は推論されます。
7const App = ({ message }: AppProps) => <div>{message}</div>;
8
9// もし返り値として違う方を返したときにエラーになるように、返り値の型を注釈することもできます
10const App = ({ message }: AppProps): JSX.Element => <div>{message}</div>;
11
12// インラインで型宣言をすることもできます。propsの型の命名を省くことができますが、くどく見えます
13const App = ({ message }: { message: string }) => <div>{message}</div>;
GitHub - typescript-cheatsheets/react: Cheatsheets for experienced React developers getting started with TypeScript
GitHub - typescript-cheatsheets/react: Cheatsheets for experienced React developers getting started with TypeScript

GitHub - typescript-cheatsheets/react: Cheatsheets for experienced React developers getting started with TypeScript

Cheatsheets for experienced React developers getting started with TypeScript - GitHub - typescript-cheatsheets/react: Cheatsheets for experienced React developers getting started with TypeScript

React v18 による変更

React 18 では、@types/react で、私たちが長い間抱えていた問題を修正する機会を得ました。私たちはもともと React 17 でこれらを修正したかったのですが、React 17 が段階的な移行を可能にする大きなステップだったため、保留にしていました。これらの変更の 1 つは、React.FunctionComponent 型における暗黙の children の削除です。なぜこの変更を行いたいのか、どのようにすれば移行を楽にできるのかを説明していこうと思います。

Removal of implicit children
Removal of implicit children

Removal of implicit children

Explainer why we intend to get rid of implicit children in `@types/react`

FC に暗黙の children が渡されなくなった

React v18 以降では、以下のコードが動かなくなる:

1import * as React from "react";
2
3const Input: React.FC = ({ children }) => <div>{children}</div>;
4// ^^^^^^^^ will error with "Property 'children'
5// does not exist on type '{}'.

一言でいうと、v18 以降の FC はそれまでの VFC になった。

VFC が非推奨になった

なった。

Q. なんでこんなことしたの?

A. 暗黙の children は、確かに component を素早くタイプできるのはいいのですが、さまざまなバグも隠されてしまいます。

Removal of implicit children
Removal of implicit children

Removal of implicit children

Explainer why we intend to get rid of implicit children in `@types/react`

React.FC から暗黙の children を削除することは、具体的には次の点で効果があるとのこと:

  • React.FC と単純な function 宣言との間で、挙動の一貫性がとれる
  • 余剰な children が props として与えられたときにエラーになる

これからどう書くか

大きく 2 つに分けられると思っています。(他あったら教えてください) これに関してはチームで統一する必要があると思っています。

FC を使う

ありです。 あえてデメリットを挙げるなら、「React FC」とかで検索すると v17 までの記事が結構でてきて、「FC より VFC を使うべき!」みたいなこと書かれてるのがちょっと怖いかなって思っています。

1// 普通のコンポーネントの書き方
2export const Button: FC<{ text: string }> = ({ text }) => {
3 return <button>{text}</button>;
4};
5
6// childrenが必要なコンポーネントの書き方(PropsWithChildrenを使う書き方もあるようです)
7export const Layout: FC<{ children: ReactNode }> = ({ children }) => {
8 return (
9 <>
10 <Header />
11 {children}
12 <Footer />
13 </>
14 );
15};

JSX.Element を使う

ありです。ちなみに僕はこっち派です。 理由はこれまでそうしてきて、v18 でも特に書き方は変わらないみたいなので...。 デメリットとしては冒頭にうひょさんのツイートにあるように次の点にあるみたいです:

  • 関数の返り値の型を推論させる必要がある
  • 引数と返り値の型を 2 箇所書く必要がある
1// 普通のコンポーネントの書き方
2export const Button = ({ text }: { text: sring }): JSX.Element => {
3 return <button>{text}</button>;
4};
5
6// childrenが必要なコンポーネントの書き方
7export const Layout = ({ children }: { children: ReactNode }): JSX.Element => {
8 return (
9 <>
10 <Header />
11 {children}
12 <Footer />
13 </>
14 );
15};

最新の投稿