🦎

React+typescriptでGenericsなComponentを作る

2022/06/04に公開

概要

プロパティーに渡す値や関数の引数の型をジェネリスクスで変更できるコンポーネントの書き方です。実は示したコードはreact nativeで使うためにこのコードにしました。詳しくは解説を見てください。

reactのversionは17.0.1を使っています。

コード

定義

type Props<T> = {
  data: T[];
}

function GenericsComponent<T>(props: React.PropsWithChildren<Props<T>>): ReactElement<any, any> {
  return(
    <Box>...</Box>
  );
}

アロー関数で書きたければこうです。

const GenericsComponent = <T,>(props: React.PropsWithChildren<Props<T>>): ReactElement<any, any> => {
  return(
    <Box>...</Box>
  );
}

この記事とは関係ないけど<T,>ってなんや?と思った方はこちらの記事をどうぞ。
https://zenn.dev/gomo/articles/bbfd53987d7bd0

使い方

<GenericsComponent<SomeType>
  data={someTypeItems}
/>

解説

検索するとこんなコードが出てきます。

const GenericsComponent = <T,>(): React.FC<Props<T>> =>
  (props) => (
    <span>Some component logic</span>
  );

(リンク先と少し違いますがこうしないとchildrenにアクセスできません。)

使うときはこんな感じですね。

const ComponentForSomeType = GenericsComponent<SomeType>();

return(
  <ComponentForSomeType
    data={someTypeItems}
  />
)

React.FCを返すジェネリクスな関数を定義して、その関数の返り値をコンポーネントとして使っていますね。最初に示したコードは自分でわざわざpropsと返り値を下から引っ張り出しました。

https://github.com/DefinitelyTyped/DefinitelyTyped/blob/ba6265eaff3b5d7b461af1b75ca98447b6c6911e/types/react/index.d.ts#L517-L525

StackOverFlowのコードのようにReact.FCを使った方がスマートだと思います。

なぜ、最初のコードにしたかと言うとreact nativeのFast Refresh(開発時に保存すると自動で読み込み直して最新の状態になる)機能が効きませんでした。このコンポーネントを使っている親コンポーネントを保存するとリロードされますが、めんどくさいので最初に示したコードで対応しました。react nativeでなければこっちを使った方がいいと思います。あるいはreact nativeでFast Refreshを効かせる方法があったらコメントでいただけると嬉しいです。

Discussion