Reactでスプレッド構文を活用してスタイルの違うボタンを使い回す

## はじめに
以下のようなボタンをReactで作る際に、同じ形をしたボタンをページ内で何度も使用する機会があり、毎回スタイリングするのが手間だったので、共通化した際にスプレッド構文が活躍したのでメモします。
![スクリーンショット 2021-01-31 0.24.44.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/493982/cdeab781-79e7-8fa5-33b8-98d2e4ccca65.png)

## ボタンのスタイル
冒頭で示したボタンのCSSは以下になりますが、これをボタン登場の度書くのは面倒です。
今回はTypeScript環境という前提なので、拡張子tsxファイルで実装していきます。

```react:App.tsx
import React from 'react';

export const App = () => {
  return (
      <a style={{ textDecoration: "none" }} href="/">
        <div style={{
          backgroundColor: "#000000",
          width: 200,
          display: "flex",
          justifyContent: "center",
          alignItems: "center",
          borderRadius: 35,
          cursor: "pointer",
          userSelect: "none",
          fontFamily: "Kozuka Gothic Pr6N",
        }}>
          <span style={{ fontSize: 17, color: "#FFFFFF", padding: "10px 0" }}>
            ボタン
          </span>
        </div>
      </a>
  );
}
```
そこで、ある程度共通の部分以外はpropを使って変更が効くように、別コンポーネントに切り出します。

```react:Button.tsx
import React from 'react'

type ButtonProps = {
  link: string
  title: string
  width: number
  backgroundColor: string
  padding: string
  color: string
  fontSize: number
  fontFamily: string
}

export const Button: React.FC<ButtonProps> = (props) => {
  return (
    <a style={{ textDecoration: "none" }} href={props.link}>
      <div style={{
        display: "flex",
        justifyContent: "center",
        alignItems: "center",
        borderRadius: 35,
        cursor: "pointer",
        userSelect: "none",
        backgroundColor: props.backgroundColor,
        width: props.width,
        fontFamily: props.fontFamily
      }}>
        <span style={{
          fontSize: props.fontSize,
          color: props.color,
          padding: props.padding
        }}>
          {props.title}
        </span>
      </div>
    </a>
  )
}
```
すると以下のように、使い回しが可能になりました。

```react:App.tsx
import React from 'react';
import { Button } from './Button';

const App = () => {
  return (
    <div>
      <Button
        title="お問い合わせ"
        width={210}
        backgroundColor="#87CEEB"
        padding="15px 0"
        color="#FFFFFF"
        fontSize={17}
        link="/"
        fontFamily="Kozuka Gothic Pr6N"
      />
    </div>
  );
}

export default App;
```
![スクリーンショット 2021-01-31 11.00.05.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/493982/e1d26a88-43d5-35c3-74ed-4643dd36b238.png)
更にボタンごとにアレンジをする場合、スプレッド構文が役に立ちました。
例えば、共通のButtonコンポーネントに更に**`customButtonStyle`**と**`customTextStyle`**を渡すことにします。

```react:App.tsx
<Button
  link="/"
  title="資料請求はこちらから"
  width={250}
  backgroundColor="#FA8072"
  padding="10px 0"
  color="#FFFFFF"
  fontSize={17}
  fontFamily="Kozuka Gothic Pr6N"
  customButtonStyle={{
    border: "2px solid #DC143C",
    borderRadius: 30,
    boxShadow: "0px 6px 11.96px 1.04px rgba(30, 30, 30, 0.13)",
  }}
  customTextStyle={{
    letterSpacing: 3
  }}
/>
```

次に**`customButtonStyle`**と**`customTextStyle`**をpropsに追加します。これは渡される時と渡されない時があると思うので、**`customButtonStyle?`**のようにundefinedを許可します。

```react:Button.tsx
import React from 'react'

type ButtonProps = {
  link: string
  title: string
  width: number
  backgroundColor: string
  padding: string
  color: string
  fontSize: number
  fontFamily: string
  customButtonStyle?: React.CSSProperties
  customTextStyle?: React.CSSProperties
}
```
あとは**`...props.customButtonStyle`**のようにスプレッド構文を使用することで、柔軟にCSSを追加することができます。

```react:Button.tsx
<a style={{ textDecoration: "none" }} href={props.link}>
  <div style={{
    display: "flex",
    justifyContent: "center",
    alignItems: "center",
    borderRadius: 35,
    cursor: "pointer",
    userSelect: "none",
    backgroundColor: props.backgroundColor,
    width: props.width,
    fontFamily: props.fontFamily,
    ...props.customButtonStyle
  }}>
    <span style={{
      fontSize: props.fontSize,
      color: props.color,
      padding: props.padding,
      ...props.customTextStyle
    }}>
      {props.title}
    </span>
  </div>
</a>
```
border等を追加したボタン（練習用なのであまりイケてないですが・・）が出来ました！
![スクリーンショット 2021-01-31 11.14.47.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/493982/877209e1-4455-9640-9048-ad813154a176.png)