MUIのButtonコンポーネントをラップした「自作Buttonコンポーネント」を作ってみた

2023/07/19に公開

概要

React ビギナーが MUI の Button コンポーネントをラップした自作の Button コンポーネントを作ってみました。
いろいろ詰まったところや不明点があり、またいつか実装する際にも同じところで詰まりそうなのでまとめておきます。

環境

react@18.2.0
react-router-dom@6.13.0
mui/material@5.13.5

コード

コンポーネント
import { Button as MuiButton, ButtonProps as MuiButtonProps } from '@mui/material';
import { SxProps, Theme } from '@mui/material/styles';
import { LinkProps } from 'react-router-dom';

type ButtonType = {
    component?: React.ForwardRefExoticComponent<LinkProps & React.RefAttributes<HTMLAnchorElement>>;
    to?: string;
    sx?: SxProps<Theme>;
} & MuiButtonProps;

export const Button = (props: ButtonType) => {
    const { children, sx = [], ...buttonProps } = props;
    return (
        <>
            <MuiButton
                sx={[{ height: '50px', borderRadius: '5px' }, ...(Array.isArray(sx) ? sx : [sx])]}
                {...buttonProps}
            >
                {children}
            </MuiButton>
        </>
    );
};
呼び出し側
<Button variant="outlined" size="large" component={Link} to="/link">
    戻る
</Button>

ポイント

Property 'component' does not exist on type ...

調査

単純に MUI コンポーネントをラップした場合、こちらのエラーが発生すると思います。

解消には以下が参考になりました。
https://stackoverflow.com/questions/74916710/property-component-does-not-exist-reactjs-materialui-typescript

To be able to use the component prop, the type of the props should be used with type arguments. Just use React.ElementType as mentioned in the docs.

自作のコンポーネントでは component prop を定義する必要があるようです。

また、MUI の マニュアルに component prop について以下の記載がありました。

The component used for the root node. Either a string to use a HTML element or a component.

MUI のコンポーネントを直接呼び出す場合は component prop を指定できるが、ラップすると不可ということ?
root node とかが絡んでくるのかな・・・?後でつよい人に質問してみたい

解消

実際に定義したのは以下です。

propsの定義
import { Button as MuiButton, ButtonProps as MuiButtonProps } from '@mui/material';
type ButtonType = {
    component?: React.ForwardRefExoticComponent<LinkProps & React.RefAttributes<HTMLAnchorElement>>;
    to?: string;
} & MuiButtonProps;
  • component と to プロパティを追加
  • MUI Button コンポーネントの props を import して型を結合

がポイントになります。

sx プロパティのデフォルト値を設定し上書き可能にする

基本となる Button コンポーネントは高さなどを統一し、sx プロパティでマージンなどを適宜指定したいと思いました。

調査

参考になったのはこちらの公式ページ
ほぼそのまま使いましたが問題なく動作しました。

import {
  Button as MuiButton,
  ButtonProps as MuiButtonProps,
} from "@mui/material";
import { SxProps, Theme } from "@mui/material/styles";
import { LinkProps } from "react-router-dom";

type ButtonType = {
  component?: React.ForwardRefExoticComponent<
    LinkProps & React.RefAttributes<HTMLAnchorElement>
  >;
  to?: string;
  sx?: SxProps<Theme>; //追加
} & MuiButtonProps;

export const Button = (props: ButtonType) => {
  const { children, sx = [], ...buttonProps } = props; //追加
  return (
    <>
      <MuiButton
        sx={[
          { height: "50px", borderRadius: "5px" },
          ...(Array.isArray(sx) ? sx : [sx]), //追加
        ]}
        {...buttonProps}
      >
        {children}
      </MuiButton>
    </>
  );
};

初期値で定義した height 50px は sx プロパティで上書きすることが可能となりました。
※props の渡し方はこちらの記事が参考になりました。
https://qiita.com/Yametaro/items/814f40d08e9d30584e20

まとめ

調べつつ何とか動くコンポーネントを作ることができました。
不明点については後ほど確認したいです。

GitHubで編集を提案

Discussion