Emotionを使ったReactコンポーネントのスタイリング(@emotion/react)

## アジェンダ
Emotionは、強力なCSS-in-JSライブラリで、Reactコンポーネントにスタイルを簡単に適用できます。しかし、コンポーネント内にスタイルを直接定義するのではなく、スタイルを別ファイルに分けて管理したい場合があります。この記事では、Emotionを使ってスタイルを別ファイルに分離し、Reactコンポーネントに適用する方法について簡単にまとめます。

## Emotionのインストール
以下のコマンドでモジュールをインストールできます。
```sh
npm install --save @emotion/react
```

## スタイルの分離と適用の基本
### 1. スタイル定義ファイルを作成

まず、スタイル定義を別ファイルに分けます。たとえば、`styled.ts`というファイルを作成し、Emotionの`css`関数を使ってスタイルを定義します。

```ts:styled.ts
import { css } from "@emotion/react";

export const buttonStyle = css`
  background: #fff;
  border: 1px solid #999;
  padding: 10px 20px;
`;
```

このファイルには、コンポーネントに適用するための基本的なスタイルが定義されています。このスタイルをReactコンポーネントで使用します。

### 擬似要素とホバーエフェクトの追加

次に、擬似要素を使ってボタンにアイコンを追加し、ホバー時にそのアイコンの色が変わるスタイルを定義します。

```ts:styled.ts
import { css } from "@emotion/react";

export const buttonStyle = css`
  background: #fff;
  border: 1px solid #999;
  padding: 10px 20px;
  position: relative;

  &::before {
    content: "✔";
    position: absolute;
    left: 10px;
    top: 50%;
    transform: translateY(-50%);
    font-size: 16px;
    color: #ffcc00;
    transition: color 0.3s ease;
  }

  &:hover {
    background-color: #eee;

    &::before {
      color: #ff6600;
    }
  }
`;
```

この例では、`::before`擬似要素を使ってボタンにチェックマークを追加し、ホバー時にその色が変わるように設定しています。

### 2. コンポーネントでスタイルを適用

次に、スタイルを適用するReactコンポーネントを作成します。ここでは、`CustomButton.tsx`というコンポーネントを例に説明します。

```tsx:CustomButton.tsx
import { FunctionComponent } from "react";
import { Symbol } from "../../types/index";
import { buttonStyle } from "./styles";
import { css, ClassNames } from "@emotion/react";

type ButtonProps = {
    label: Symbol;
    onClickHandler: () => void;
}

export const CustomButton: FunctionComponent<ButtonProps> = ({ label, onClickHandler }: ButtonProps) => {
    return (
        <ClassNames>
            {({ css }) => (
                <button className={css(buttonStyle)} onClick={onClickHandler}>
                    {label}
                </button>
            )}
        </ClassNames>
    );
}
```

ここで、`ClassNames`コンポーネントを使用して、スタイルを`className`プロパティに適用しています。これにより、`css`関数を適切に適用でき、外部ファイルからスタイルをインポートして使用することが可能になります。

### 複数のクラスを組み合わせる

前述の方法では、1つのクラス名を適用する例を示しましたが、複数のクラスを適用したい場合もあります。これを実現するには、`ClassNames`コンポーネントを使用し、テンプレートリテラルで複数のクラスを組み合わせることができます。

```tsx:CustomButton.tsx
import { FunctionComponent } from "react";
import { Symbol } from "../../types/index";
import { buttonStyle, hoverStyle } from "./styles";
import { css, ClassNames } from "@emotion/react";

type ButtonProps = {
    label: Symbol;
    onClickHandler: () => void;
}

export const CustomButton: FunctionComponent<ButtonProps> = ({ label, onClickHandler }: ButtonProps) => {
    return (
        <ClassNames>
            {({ css }) => (
                <button className={css`${buttonStyle} ${hoverStyle}`} onClick={onClickHandler}>
                    {label}
                </button>
            )}
        </ClassNames>
    );
}
```

このように、テンプレートリテラルを使用して、`buttonStyle`と`hoverStyle`を1つの`className`プロパティにまとめて適用することができます。これにより、複数のスタイルを組み合わせてボタンに適用できます。

**この記述方法はクラスを1つのみ適用したい場合でも使用できます。**

### 3. フォルダ構成

このアプローチを使用する際のフォルダ構成の例は以下の通りです。

```
project-root/
├── src/
│   ├── components/
│   │   ├── CustomButton.tsx
│   │   └── styled.ts
│   ├── types/
│   │   └── index.ts
│   └── ...
```

`CustomButton.tsx`ファイルで定義したスタイルを、`styled.ts`からインポートして使用しています。これにより、コンポーネントのロジックとスタイルが分離され、コードがより管理しやすくなります。

## まとめ
Emotionを使用することで、Reactコンポーネントのスタイルを簡単に適用できます。さらに、スタイルを外部ファイルに分離することで、コードの再利用性が高まり、コードベースのメンテナンスが容易になります。また、擬似要素やホバーエフェクトを組み合わせることで、リッチなUIを作成できます。

## 参考
- [Emotion – Install](https://emotion.sh/docs/install)
- [Emotion – @emotion/react](https://emotion.sh/docs/@emotion/react)
- [【React × Emotion】疑似要素の使い方 | SCRAWLED TECH BLOG](https://scrawledtechblog.com/react-emotion-giji/)