Styled Components v4について

emotionがアツいとのことで、触ってみたい感はすごくあるのですが
ここではStyled Components v4が結構便利なので紹介させていただきたいと思います。


## すごく早くて軽くなった

* 16.1kBから15kB未満に
* マウント時に約25％の高速化
* 再レンダリング時に約7.5％の高速化

## createGlobalStyle

`injectGlobal`に代わって`createGlobalStyle`というAPIができました。
通常、styled componentsは自動的にローカルスコープになるため、他のコンポーネントから分離されます。
そこがいいところなのですが、bodyの値とかを一括で変えたいときに困ります。

bodyとかのスタイリングをしたいときにとても便利です。

もともと`injectGlobal`というものがありましたが、動的なアップデートやホットリロードが出来なかったり、コンポーネントとして利用できなかったりでした。


```react
import React from 'react';
import styled , { createGlobalStyle } from 'styled-components';

const GlobalStyle = createGlobalStyle`
  body {
    color: ${props => (props.whiteColor ? 'white' : 'black')};
    background: #333;
  }
`
export default () => <React.Fragment>
  <GlobalStyle whiteColor/>
  Hello React
</React.Fragment>
```

![image.png](https://qiita-image-store.s3.amazonaws.com/0/154239/50c38c89-68a2-0aab-4e18-42c1ae4e3a22.png)


## "as" prop

styleがあてられたコンポーネントを別のタグで利用したい場合に使います。
`.withComponent`の代わりとなる機能です。

```react
import React from 'react';
import styled from 'styled-components';

const GrayArea = styled.div`
  background: #333;
  color:white;
`
export default () => <React.Fragment>
  <GrayArea as='button' onClick={() => alert('It works!')}>
    Hello React
  </GrayArea>
</React.Fragment>
```

GrayAreaはdivとして作られているが、`as='button'`を使うことでbuttonとして利用できます。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/154239/84514e2c-e470-b295-666a-0dbd5c3db35e.png)

## .extendの廃止

コンポーネントを拡張する場合には、`Comp.extend`に代わり`styled(Comp)`と記述するように統一されました。

```react
import React from 'react';
import styled from 'styled-components';

const Button = styled.button`
  background: #333;
  color: white;
`

const RedButton = styled(Button)`
  background: red;
`

export default () => <React.Fragment>
  <RedButton  onClick={() => alert('It works!')}>
    Hello React
  </RedButton>
</React.Fragment>
```

![image.png](https://qiita-image-store.s3.amazonaws.com/0/154239/59448fed-5411-2c0c-f7c3-ba6984aa9e81.png)

## Strict Modeへの完全対応

[Strict Mode](https://reactjs.org/docs/strict-mode.html)に準拠する形になっています。

## refのネイティブサポート

`innerRef`が廃止されたことによる対応です。

```react
import React from 'react';
import styled from 'styled-components';

const Input = styled.input`
  padding: 0.5em;
  background: #333;
  color: white;
`

export default class Form extends React.Component {
  constructor(props) {
    super(props);
    this.inputRef = React.createRef();
  }

  render() {
    return (
      <Input
        ref={this.inputRef}
        placeholder="Hover to focus!"
        onMouseEnter={() => {
          this.inputRef.current.focus()
        }}
      />
    );
  }
}

```

![image.png](https://qiita-image-store.s3.amazonaws.com/0/154239/1a500eee-8277-ee2c-2ad4-862e8c1b80ce.png)

## css prop

いちいちコンポーネントを作るのが面倒な場合に、以下のように書けるようになりました。
[babel plugin](https://www.styled-components.com/docs/tooling#babel-plugin)が必要で、実際には下のように変換されます。

```react
<div
  css={`
    background: papayawhip;
    color: ${props => props.theme.colors.text};
  `}
/>
<Button
  css="padding: 0.5em 1em;"
/>
```

```react
const StyledDiv = styled.div`
  background: papayawhip;
  color: ${props => props.theme.colors.text};
`

const StyledButton = styled(Button)`
  padding: 0.5em 1em;
`

<StyledDiv />
<StyledButton />
```

## Theme Consumer

Context APIのConsumerコンポーネント。
ThemeProviderにて注入された状態を利用したConsumerが作成できるようになりました。

```react
import React from 'react';
import styled, { ThemeProvider , ThemeConsumer} from 'styled-components';

const Child = () => <div>
  <ThemeConsumer>
    {theme => <div>The theme color is {theme.color}.</div>}
  </ThemeConsumer>
</div>

export default () => <ThemeProvider theme={{ color: 'black' }}>
  <Child/>
</ThemeProvider>
```

![image.png](https://qiita-image-store.s3.amazonaws.com/0/154239/b54f3ce4-c7d6-46be-f1db-59f57c8f2972.png)



## 移行について

以前のバージョンを利用している場合、[codemods](https://github.com/styled-components/styled-components-codemods)を利用して変換を行うことができます。

グローバルインストールして


```bash
npm install -g styled-components-codemods
```

コマンドを叩く

```bash
styled-components-codemods v4 src/**/*.js
```

`Comp.extend`と`injectGlobal`が状況に応じて置換されます。