【React】Reactの基本的なスタイリング方法４つのまとめ

Reactのスタイリング方法についてまとめてみました。

※CSS Moduleは近い将来廃止される可能性があるため、まとめから省く。

# ■インラインスタイル
CSSスタイルの記述をJavascriptのオブジェクトと同じような形で記載する。
スタイルはHTMLタグに対して直接設定する。

**例**

```react
export default function App() {
  const style = {
    width: 120,
    height: 60,
    display: "block",
    fontWeight: "bold",
    backgroundColor: "green"
  };

  return <button style={style}>ボタン</button>;
}
```

**補足**

オブジェクトなので、以下のように三項演算子などを用いて、
動的に変更することが可能。

```react
{     
   background: 何かしらの処理 ? "pink": "",
}
```

## ■注意点

### ・pxは単位は省略できる
インラインスタイルでは、pxは単位を省略すると、React側が自動でpxと認識してくれる。

<font color="blue">※逆にいうと、省略したら必ずpxとして反映されてしまうので、px以外をつけたい場合は注意。</font>
<br>
<br>

### ・プロパティ名はキャメルケース
プロパティ名は通常のCSSと違い、`キャメルケース`で記述する。
```react
{
    width: 120,
    height: 60,
    display: "block",
    fontWeight: "bold",
    backgroundColor: "green"
  }
```

しかし、プロパティ名を`文字列`で記載する場合は、CSS同様`ケバブケース`で記述する。
```react
{
    width: 120,
    height: 60,
    display: "block",
    fontWeight: "bold",
    "background-color": "green",
    "border-radius": 999,
  }
```
<br>
<br>

### ・擬似要素・擬似セレクタ・メディアクエリは使用できない。

インラインスタイルはHTMLタグに直接付けるのが前提なので、HTMLタグに直接設定できないCSSは使用できない。
<br>
<br>

### パフォーマンスの低下
インラインスタイルはHTMLタグが読み込まれた時にスタイルの計算が全て行われるので、再レンダリング等で読み込まれる度に再計算される。
よって、パフォーマンスが低下する。
<br>
<br>

# ■外部のCSSを読み込む
作成したCSSファイルをimportして読み込む。
通常のCSSの使い方にかなり近い。

**example.css**
```css
.btn {
    margin: auto;
    border-radius: 9999px;
    border: none;
    display: block;
    width: 120px;
    height: 60px;
    font-weight: bold;
    cursor: pointer;
}

.selected {
    background-color: pink;
}

.space {
    margin-bottom: 20px;
}
```


```react
import "./Example.css" // CSSをimport

const Example = () => {

  return (
    <>
    {// ""で読み込み可能。}
    <div className="space"> 
      <button className="btn">
        ボタン
      </button>
    </div>

    {// {}でも読み込み可能。}
    <div className={"space"}> 
      <button className={"btn"}>
        ボタン２
      </button>
    </div>
    </>
  );
};

export default Example;
```

**補足**

こちらも三項演算子などでクラスを動的に変えることで、スタイルを変更することが可能。
```react
import { useState } from "react";
import "./Example.css"

const Example = () => {
  const [isSelectedA, setIsSelectedA] = useState(false);

  const [isSelectedB, setIsSelectedB] = useState(false);

  const clickHandlerA = () => setIsSelectedA((prev) => !prev);
  const clickHandlerB = () => setIsSelectedB((prev) => !prev);

  return (
    <>
    <div className={"space"}>
      <button className="btn" onClick={clickHandlerA}>
        ボタン
      </button>
    </div>

    <div>
      <button className={isSelectedB ? "selected btn" : "btn"} onClick={clickHandlerB}>
        ボタン２
      </button>
      <div style={{ textAlign: "center" }}>
        {(isSelectedA || isSelectedB) && "クリックされました。"}
      </div>
    </div>
    </>
  );
};

export default Example;
```

**補足２**

三項演算子の箇所は、下記のようにテンプレートリテラルを利用して記載することも可能。

```react
 <button className={`btn ${isSelected ? "selected" : ""}`} onClick={clickHandlerB}>
        ボタン２
      </button>
```

## ■注意点

### ・コンポーネントごとにスタイルを分けられない

外部読み込みのスタイル適応方法では、コンポーネント単位でスタイルを分けるということができない。

**修正前**

![スクリーンショット 2022-12-21 22.16.36.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/754263/54df772c-cd39-b9b7-7044-7b0a12485129.png)

**ディレクトリ構造**
```
root/
　├ components/
　├      └ SubButton.js
　├      └ SubButton.css
　│　
　├ Example.js 
　└ Example.css
```

**css**
```css
/* Example.css */
.btn {
    margin: auto;
    border-radius: 9999px;
    border: none;
    display: block;
    width: 120px;
    height: 60px;
    font-weight: bold;
    cursor: pointer;
}


/* SubButton.css */
.btn {
    margin: auto;
    border-radius: 9999px;
    border: none;
    display: block;
    width: 120px;
    height: 60px;
    font-weight: bold;
    cursor: pointer;
    background-color: blue;
}
```
**SubButton.js**

```react
import "./SubButton.css"

const SubButton = () => {

  return (
    <>
    <div className={"space"}>
      <button className="btn">
        ボタン
      </button>
    </div>
    </>
  );
};

export default SubButton;
```

**Example.js**

```react
import { useState } from "react";
import SubButton from "./components/SubButton";
import "./Example.css"

const Example = () => {

  return (
    <>
    <div className={"space"}>
      <button className="btn" onClick={clickHandlerA}>
        ボタン
      </button>
    </div>

    <div className={"space"}>
      <button className={isSelectedB ? "selected btn" : "btn"} onClick={clickHandlerB}>
        ボタン２
      </button>
    </div>

    <biv className={"space"}>
      <SubButton />
    </biv>
    </>
  );
};

export default Example;

```

**結果**
![スクリーンショット 2022-12-21 22.27.55.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/754263/3fd7c674-f2b9-b58c-55d8-29ff90cde9cd.png)

上記のように、SubButton.cssの内容が全てに適応されてしまう。
これは、外部からの読み込みはグローバルスコープとして採用されてしまうのと、
cssが後から読み込まれたものを採用するというデフォルトの仕様があるからである。
<br>
<br>

# ■styled-Component

よく使われているReactのスタイリングライブラリ。

### ①利用方法
ライブラリをインストール
```
npm install --save styled-components
```

### ②コンポーネントでimport
```react
import styled from "styled-components";

const Example = () => {
  return ;
}
```
**ポイント**

<font color="red">このimportした styledには、HTMLタグのプロパティをデフォルトで保有している。プロパティの数はHTMLタグの数だけある。</font>

### ③スタイルを定義
styled-componentsでは、スタイルを`タグ付きテンプレート`という記法で記載する。
※なぜこの記法なのかの詳しい理由は不明です...。

タグ付きテンプレートについては以下を参照。

https://penpen-dev.com/blog/tag-literal-template/

```react
import styled from "styled-components";

const Example = () => {

  const StyledButton = styled.button`
    margin: auto;
    border-radius: 9999px;
    border: none;
    display: block;
    width: 120px;
    height: 60px;
    font-weight: bold;
    cursor: pointer;
  `;

  return (
    <>
    <StyledButton>ボタン</StyledButton>
    </>
  );
};

export default Example;
```

上記のように、定義した StyledButtonをコンポーネントにして利用することでスタイルを反映させる。

**補足**

**styled-componentsでは、スタイルのコンポーネントに`props`を渡すこともできる。**


```react
import { useState } from "react";
import styled from "styled-components";

const Example = () => {
  const [isSelected, setIsSelected] = useState(false);

  const clickHandler = () => setIsSelected((prev) => !prev);

  const StyledButton = styled.button`
    margin: auto;
    border-radius: 9999px;
    border: none;
    display: block;
    width: 120px;
    height: 60px;
    font-weight: bold;
    cursor: pointer;
    background: ${(props) => props.isSelected ? 'pink' : ''};
  `;

  return (
    <>
    <StyledButton isSelected={isSelected} onClick={clickHandler}>ボタン</StyledButton>
      <div style={{ textAlign: "center" }}>
        {isSelected && "クリックされました。"}
      </div>
    </>
  );
};

export default Example;
```

※タグ付きテンプレート内は文字列なので、変数を使用する場合はテンプレートリテラルでの記載となる。


**補足②**

**継承をすることができる。**

ほど同じ内容で一部違うようなスタイルコンポーネントを作成したいときなどに有効。

```react
  const StyledButton = styled.button`
    margin: auto;
    border-radius: 9999px;
    border: none;
    display: block;
    width: 120px;
    height: 60px;
    font-weight: bold;
    cursor: pointer;
    background: ${(props) => props.isSelected ? 'pink' : ''};
  `;

  const OrangeButton = styled(StyledButton)`
    background-color: orange;
  `;

  return (
    <>
    <StyledButton isSelected={isSelected} onClick={clickHandler}>ボタン</StyledButton>
    <OrangeButton>ボタン</OrangeButton>
    </>
  );
```

**CSSのスタイルは全て利用できる ＋ ネスト記法も可能。**

他のスタイリングとは違い、CSSは基本全て利用できる。
メディアクエリや擬似セレクタ等も利用可能。

また、通常のCSSでは利用できないSaSSのネスト記法も利用することが可能。

**コンポーネントタグ内のspanタグのCSSを設定する。**
```react
  const OrangeButton = styled(StyledButton)`
    background-color: orange;

    :hover {
      color: red;
      opacity: 0.7;
    }
　　　　　　　/*　ネスト記法 */
    span { 
      background-color: black;
      color: white;
    }
  `;

 <OrangeButton><span>ボタン</span></OrangeButton>

```