Reactの高階コンポーネントのメモ

# はじめに

React の高階コンポーネントのメモです。
ご指摘、感想、お待ちしています。。。

## 目次

1. 高階コンポーネント？？？
2. まずは普通に書いてみる
3. 高階コンポーネントを作成
4. 高階コンポーネントをくっ付ける
5. まとめ

## 1. 高階コンポーネント？？？

高階コンポーネントとは。。。
[公式の Docs](https://ja.reactjs.org/docs/higher-order-components.html)
以下は、引用です。

> 高階コンポーネント (higher-order component; HOC) はコンポーネントのロジックを再利用するための
> React における応用テクニックです。HOC それ自体は React の API の一部ではありません。
> HOC は、React のコンポジションの性質から生まれる設計パターンです。

さらにさらに。

> 具体的には、高階コンポーネントとは、あるコンポーネントを受け取って新規のコンポーネントを返すような関数です。

ほうほう、どうやらコンポーネントのロジックを再利用（＝使い回す）ためのテクニックなのか。。
では、実際に書いてみよう。

## 2. まずは普通に書いてみる

簡単なカウンターのコンポーネントを 2 つ用意します。
カウントの条件は以下

- ボタンのクリック
- マウスでホバー

```jsx:ClickCounter
import React, { Component } from "react";

class ClickCounter extends Component {
  constructor(props) {
    super(props);
    this.state = {
      count: 0
    };
  }

  incrementCount = () => {
    this.setState(prevState => {
      return { count: prevState.count + 1 };
    });
  };

  render() {
    return (
      <div>
        <button onClick={this.incrementCount}>
          clicked {this.state.count} times
        </button>
      </div>
    );
  }
}

export default UpdatedComponent(ClickCounter);
```

```jsx:HoverCounter
import React, { Component } from "react";

class HoverCounter extends Component {
  constructor(props) {
    super(props);
    this.state = {
      count: 0
    };
  }

  incrementCount = () => {
    this.setState(prevState => {
      return { count: prevState.count + 1 };
    });
  };

  render() {
    return (
      <div>
        <h3 onMouseOver={this.incrementCount}>
          Hover {this.state.count} times
        </h3>
      </div>
    );
  }
}

export default HoverCounter;
```

ここで、各コンポーネントで共通の箇所は以下の部分です。

```jsx
constructor(props) {
        super(props)
        this.state = {
            count: 0
        }
    }

incrementCount = () => {
    this.setState(prevState => {
        return { count: prevState.count + 1 }
    })
}

```

## 3. 高階コンポーネントを作成

冒頭の引用にあるように
> あるコンポーネントを受け取って新規のコンポーネントを返すような関数です。
 
高階コンポーネントを作成しましょう。

- 高階コンポーネント : `higherOrderComponent`
- 受け取るコンポーネント : `OriginalComponent`
- 新規のコンポーネント : `NewComponent`

`NewComponent`で共通箇所として注目した

- `count`
- インクリメントに必要な`incrementCount`

を定義しています。
それらを、`OriginalComponent`のpropsとして持たせてあげます。

```jsx:higherOrderComponent
import React from 'react'

const higherOrderComponent = OriginalComponent => {
    class NewComponent extends React.Component {

        constructor(props) {
            super(props)

            this.state = {
                count: 0
            }
        }

        incrementCount = () => {
            this.setState(prevState => {
                return { count: prevState.count + 1 }
            })
        }

        render() {
            return <OriginalComponent count={this.state.count} incrementCount={this.incrementCount}/>
        }
    }
    return NewComponent
}
export default higherOrderComponent
```

## 4. 高階コンポーネントをくっ付ける

高階コンポーネントを利用してみましょう。
`higherOrderComponent(ClickCounter)`の箇所で利用がされています。
そうすると、`count`や`incrementCount`は高階コンポーネントがpropsで渡してくれているので
各コンポーネントで定義やロジックの実装が不要になります。

```jsx:ClickCounter
import React, { Component } from 'react'
import higherOrderComponent from './Counter'

class ClickCounter extends Component {

    render() {
        return (
            <div>
                <button onClick={this.props.incrementCount}>clicked {this.props.count} times</button>
            </div>
        )
    }
}

export default higherOrderComponent(ClickCounter)
```

```jsx:HoverCounter
import React, { Component } from 'react'
import higherOrderComponent from './Counter'

class HoverCounter extends Component {

    render() {
        return (
            <div>
                <h3 onMouseOver={this.props.incrementCount}>Hover {this.props.count} times</h3>
            </div>
        )
    }
}

export default higherOrderComponent(HoverCounter)

```

## 5. まとめ
高階コンポーネントを利用して、コンポーネントのロジックを共通化できました。
めでたし、めでたし。
おしまい。