コンポーネントをくっつける
これは私の好きな手です。Shopifyとかがやってたテクで、私は外国の方のコード見て「かっこいいな!」って思った。他にはRadix UIとかみたいな。それをパクりました。 あるFCコンポーネントにプロパティをくっつけたり、あるいはオブジェクトとしてまとめてエクスポートします。
Card.Header = CardHeader;
Card.Body = CardBody;
Card.Divider = Divider;
Card.Footer = CardFooter;
export { Card };
私のソースコードから抜粋しますが、こんな感じに好きなパーツを取り出して書くことが出来るんですよ。直感的な気がしていて、この考え方は私のお気に入りです。
export const EditArea = () => {
const { imageFile } = useImageFile();
if (imageFile === null) return null;
return (
<EditForm.Provider
initialValue={{
width: imageFile.width,
height: imageFile.height,
format: imageFile.format,
}}
>
<motion.div
initial={{ opacity: 0, y: 10 }}
animate={{ opacity: 1, y: 0, transition: { duration: 0.3 } }}
>
<Card.Header className="px-6 flex justify-between gap-3">
<FileName name={imageFile.name} />
<EditMenu />
</Card.Header>
<Card.Divider />
<EditForm.Form>
<Card.Body className="flex px-6 my-2 justify-center items-center">
<ImageView dataUrl={imageFile?.data_url} />
<EditForm.Body />
</Card.Body>
<Card.Divider />
<Card.Footer>
<EditForm.SubmitButton />
</Card.Footer>
</EditForm.Form>
</motion.div>
</EditForm.Provider>
);
};
ComponentProps
これも好きな手です。ReactにはComponentProps
ないし、ComponentPropsWithRef
, ComponentPropsWithoutRef
って型があります。
特定のコンポーネントのPropsの型を持ってこれるってものですね。これも海外の人のリポジトリ漁ってて学んだんだけど、意外と知名度低い気がするんですよね、、
以下に私のソースコードの例を示します。
export interface ThemeButtonProps {
variant?: ComponentProps<typeof Button>["variant"];
size?: ComponentProps<typeof Button>["size"];
invisibleRing?: boolean;
}
上記の場合、一部のプロパティに他のコンポーネントのPropsを共通に使いたくて持ってくるやり方なんですが、もっと汎用的な方法があって、input
とかdiv
みたいな一般的なHTMLタグのラッパーコンポーネントをfowardRef
とかでくるむときにComponentProps
を使ってPropsの型を継承すれば、簡単に全部のタグのPropsを使えるようになります。ref
使わないならComponentWithoutRef
とかにもできる。
なぜfowardRef
が必要かと言うと、特にサードパーティのライブラリとかでちょっとしたアニメーションとかついてる場合に、ref
が必要なケースって多いんですよね。そういうときに対応できるようなコンポーネントを作れておくと、ワカランって幅が少なくなる気がします。