さっとstyled-componentsの基本を身につける

## はじめに
[前回の記事](https://qiita.com/course_k/items/b55ad8f97515f39f6aca#%E4%BA%8B%E5%89%8D%E6%BA%96%E5%82%99)でstyled-componentsを扱いましたが、実はあんまりよくわかっていません。

なので、以下の公式サイトに書いてある基本をざっくり確認していきます。

https://styled-components.com/docs/basics

### 前提
* React、TypeScriptの実行環境が整っていること
* 開発ツールはVS Codeを使用、OSはMac

## styled-componentsとは
CSSファイルを作らず、JavaScriptファイルの中にスタイルを書くCSS-in-JSの一種です。
JavaScriptのタグ付きテンプレートを使用してスタイルを定義します。

Reactのコンポーネントにどのようにスタイルをあてるか、というところから生まれたライブラリで、コンポーネントとスタイルを別々に定義する必要がありません。

作成したコンポーネント自体がスタイルの要素も持つので、どのコンポーネントがどのスタイルと結びついているかを考える必要がなく、保守性が向上します。

また、クラス名を自動で生成してくれるのでクラス名の重複やタイプミスによるバグの心配もありません。

## styled-componentsの基本
### インストール
任意のプロジェクトをVS Codeで開き、ターミナルから以下のコマンドを入力します。
```
npm install styled-components
```
これでインストールは完了です。
なお、執筆時点でのバージョンは6.1.11です。

また、VS Codeで開発する場合は「vscode-styled-components」という拡張機能をいれると便利なのでおすすめです。

### 基本のキ
まずはどのように書くかを見てみます。

```react:styled-componentsの基本形
const コンポーネント名 = styled.htmlタグ名`
   css定義
`
```

これを実際に使ってコンポーネントを生成すると以下のようになります。
```react:App.tsx
import styled from "styled-components";

const MyButton = styled.button`
  background-color: blue;
  color: white;
  border-radius: 10px;
  font-size: 24px;
  padding: 5px;
`;

const App = () => {
  return (
    <>
      <MyButton>ボタン</MyButton>
    </>
  );
};

export default App;
```
`MyButton`がstyled-componentsを使用して作成したコンポーネントです。
<img width='40%' src='https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/251137/cfdb37e6-d427-767f-d30b-7fa60085f674.png'>

生成したコンポーネントは指定したhtmlタグと同じ機能を持つため、`button`タグであれば`onClick`などの属性を指定できます。

コンポーネントとスタイルが結びついているので、CSSファイルのどこに記載があるかをいちいち探す必要がなく、コンポーネントを消せばスタイルも当然消えます。

可読性がよく、保守性も高いコードになります。

### スタイルを動的に変更する
先ほど作成した`MyButton`はコンポーネントであるので、propsを受け渡すことができます。
これにより、外部から値を受け渡すことで動的に適用するスタイルを変えられます。

```react:App.tsx
import styled from "styled-components";

const MyButton = styled.button<{ $primary?: boolean }>`
  background-color: ${(props) => (props.$primary ? "blue" : "white")};
  color: ${(props) => (props.$primary ? "white" : "blue")};
  border-radius: 10px;
  font-size: 24px;
  padding: 5px;
`;

const App = () => {
  return (
    <>
      <MyButton>普通のボタン</MyButton>
      <MyButton $primary={true}>反転したボタン</MyButton>
    </>
  );
};

export default App;
```
「普通のボタン」はpropsを渡していないので、`$primary`はfalseになります。
よって、背景が白、文字色が青のスタイルとなります。
一方、「反転したボタン」は`$primary`に`true`を設定したので、別のスタイルが適用されています。

このようにコンポーネントの外から値を渡すことで、スタイルを変更することがができました。

<img width='60%' src='https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/251137/dba99ae8-0d2d-ff29-79e1-2297b5a1ccac.png'>

この実装のポイントは3つあります。

#### 関数を使う
propsを受け取るには、関数を使う必要があります。
例えば`background-color`のプロパティに指定しているのは以下の関数です。
`(props) => (props.$primary ? "blue" : "white")`
アロー関数を使い、引数を`props`という名前で受け取り、三項演算子で返却する値を`blue`か`white`かとしています。

#### 関数を${}で囲む
忘れがちですが、スタイルを定義しているのはタグ付きテンプレート、つまりテンプレートリテラルの中です。
つまり、テンプレートリテラル内でJavaScriptの式を使用する場合は`${}`で囲む必要があります。

また`"blue"`、`"white"`のように文字列はダブルクォートまたはシングルクォートで囲む必要があります。

[基本のキ](#基本のキ)で確認したときは
`background-color:blue`
のように`blue`はクォートで囲んでいませんでした。
これはテンプレートリテラル内だったので全てが文字列として認識されるためです。

しかし、`${}`で囲まれた中は新たなJavaScriptの式を書くエリアとして認識されているので、クォートで囲み文字列として認識されるようにします。

#### props名には$をつける
$をつけない場合、設定したprops名は属性として判定され、DOMに伝搬します。
つまり、htmlのタグの属性として設定されてしまいます。
実際には、以下のようにコンソールにワーニングが出ます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/251137/5d97fe4f-8e64-f923-89ae-d24371b51753.png)
```
styled-components: it looks like an unknown prop "primary" is being sent through to the DOM, which will likely trigger a React console error. If you would like automatic filtering of unknown props, you can opt-into that behavior via `<StyleSheetManager shouldForwardProp={...}>` (connect an API like `@emotion/is-prop-valid`) or consider using transient props (`$` prefix for automatic filtering.)
```


それを避けるため、プレフィックスとして`$`をつけます。
これにより、DOMに伝搬されず、styled-components内のみで使われれるpropsを定義することができます。

これはtransient props(一時的なprops)と呼ばれるものです。

https://styled-components.com/docs/api#transient-props


### スタイルの継承
いろいろなところで使い回すボタンやインプット要素などの部品があるとします。
基本みんな同じなのですが、ある一部分で使うときだけは、ちょっとスタイルを変えたいとしましょう。

先程のpropsで動的に変えるよう修正してもよいですが、一部分の修正のためにpropsを受け取るための処理を書くのももったいない気がします。

そんなときに使えるのが、スタイルの継承です。
これは、スタイルの一部だけをかえ、ほかは同じにしたいとき使えます。

```react:App.tsx
import styled from "styled-components";

const MyButton = styled.button`
  background-color: blue;
  color: white;
  border-radius: 10px;
  font-size: 24px;
  padding: 5px;
  margin-right: 20px;
`;

const ModifiedButton = styled(MyButton)`
  background-color: orange;
  font-size: 20px;
  font-style: italic;
`;

const App = () => {
  return (
    <>
      <MyButton>普通のボタン1</MyButton>
      <MyButton>普通のボタン2</MyButton>
      <ModifiedButton>ちょっと変えたボタン</ModifiedButton>
    </>
  );
};

export default App;
```
画面は以下のようになります。
<img width='70%' src='https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/251137/f119bb94-e6bd-75d4-5331-c6d9a2db9724.png'>


ポイントは2つです。
#### styledの引数に継承したいコンポーネントを設定
継承するためには、新しくコンポーネントを定義します。
そして、その生成の際に継承元を引数に設定します。

今までは`styled.タグ名`のように「.(ドット)」を使用していましたが、継承の際は`styled(親コンポーネント)`のように関数として使用します。


#### 変更したいスタイルを定義
継承元のスタイルをすべて引き継ぐため、変えたいスタイルのみを定義します。
継承元に存在するスタイルを定義した場合は、そのスタイルを上書きします。
また、継承元にないスタイルを定義することもできます。

何度も同じことを書く必要がなく、全体の変更がある場合には継承元を修正すればよいので楽ですね。

### スタイルの継承：亜種
個人的に力技では？と思ったのですが、スタイルの継承でちょっとおもしろいものがあったので紹介します。

例えば、ボタンとリンクでまったく同じ見た目にしたい場合、先程の継承は使えません。
継承元のコンポーネントから新しいコンポーネントを生成するので、同じ種類のタグのコンポーネントしか生成できません。

そんなときは以下のようにします。
```react:
import styled from "styled-components";

const MyButton = styled.button`
  background-color: blue;
  color: white;
  border: 1px solid black;
  border-radius: 10px;
  font-size: 24px;
  padding: 5px;
  margin-right: 20px;
`;

const LinkButton = styled(MyButton)`
  display: inline-block;
  text-decoration: none;
`;

const App = () => {
  return (
    <>
      <MyButton>普通のボタン1</MyButton>
      <LinkButton as="a" href="#">
        リンクのボタン
      </LinkButton>
    </>
  );
};

export default App;
```

リンクボタン用のコンポーネントを作りました。
ここまでは先程の継承と同じです。

ポイントは`LinkButton`コンポーネントに設定している`as`属性です。
この属性にはhtmlタグを指定します。

そうすることで、実際に表示されるタグの内容をもともとの定義である`button`タグから`a`タグに変更することができます。

見た目は以下のようになります。
<img width='70%' src='https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/251137/6a3a737d-ed8c-64ba-f956-cd90625d6ba0.png'>

これを使うにはいくつか注意点があります。
まず、変更後のタグに必要な属性を定義すること。
今回の例では`a`タグに変更しているので`href`属性などが必要になります。

次に、アクセシビリティの考慮が必要です。
`a`タグをボタンタグの見た目にしているので、それがわかるようにする必要があります。

ちょっと力技かもしれませんが、うまく使えれば便利です。

## まとめ
styled-componentsの基本的な使い方を確認してきました。
これだけでも抑えておけば、サクッと簡単にスタイルを定義することができます。

冒頭に提示した公式サイトのBasicには他にもいくつかの機能があるのですが、冗長になるのでまた別の機会に扱います。