【React】ざっくり入門(Hooks)

## 概要
React16.8から新しい機能として`Hooks`が導入されました。
以下の順序で`Hooks`とは何かざっくり入門していきましょう。

- [Hooksとは？](#hooksとは)
- [Hooksの規則](#hooksの規則)
- [State Hook](#state-hook)
- [Effect Hook](#effect-hook)
- [Custom Hook](#custom-hooks)

# Hooksとは？
`Hooks`とは従来__classコンポーネント__でしか使用できなかった`state`等の機能を__functionalコンポーネント(関数コンポーネント)__でも使用可能にする機能です。

この記事では以下の3種類の`hook`を紹介します。
 
- (1)__State Hook__:`state`や`setState`を関数コンポーネント内で使用可能にする。
- (2)__Effect Hook__:データ取得やDOM変更といった`side effects `を関数コンポーネント内で使用可能にする。
- (3)__Custom Hooks__:共通のロジックをコンポーネント間での再利用を可能にする。

# Hooksの規則
`Hooks`を使用する際には以下の規則を守りましょう。

- (1) Hooksは必ずコンポーネント中の一番上(`トップレベル`)に定義する。
- ループ、条件分岐、ネストされた関数の中で定義してはいけません。)
- (2) HooksはReactの関数コンポーネントの中だけで呼ぶ。(通常のJavascriptの関数から使用してはいけません。)

# State Hook
`useState`と呼ばれるhookを使用する事で`state`や`setState`を関数コンポーネント内で行える様にします。
`classコンポーネント`と`useState`を使用した`関数コンポーネント`を比較して使用方法を確認して見ましょう。

### 従来のclassコンポーネント
以下の例では主に2つの事を行なっています。

- (1)`state`で初期値に`0`を持つ`count`を定義する。
- (2)`setState`でボタンを押すたびに`count`に`1`を足している。

![output2](https://user-images.githubusercontent.com/37989236/53772326-60197180-3f29-11e9-91a1-5901b4c26eff.gif)

```jsx
class Example extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      count: 0
    };
  }

  render() {
    return (
      <div>
        <p>{this.state.count} 回クリックしました。</p>
        <button onClick={() => this.setState({ count: this.state.count + 1 })}>
          クリックしてください。
        </button>
      </div>
    );
  }
}
```


### StateHook
上記と全く同じ事を`useState`を使用して行います。
基本的な使用方法(定義方法)は以下の通りです。

```jsx
const [state, setState] = useState(initialState);
```

`useState`では従来の`state`と`setState`を同時に設定しする様なイメージです。
上記の`count`やその`setState`を`useState`を使用して定義すると以下の様になります。

```jsx
import React, { useState } from  'react';

function Counter() {
  const [count, setCount] = useState(0)
}
```

以下の3点に注目して上のコードを見てみましょう。

- (1) `count`がclassコンポーネントでいう`this.state={count:0}`の部分。
- (2) `setCount`がclassコンポーネントでいう`setState`の部分。
- (3) `useState()`に渡されている`0`が`count`の初期値。


また以下の2点を踏まえて残りのコードを完成させます。

- (1) `state`を直接参照できる。
- (2) `setCount`を使用して`state`を更新できる。

```jsx
import React, { useState } from  'react';

function Counter() {
  const [count, setCount] = useState(0)

  return(
    <div>
      // (1) stateを直接参照できる。
      <p>{count} 回クリックしました</p>
      
      // (2) setCountを使用してstateを更新できる。
      <button onClick={() => setCount(count + 1)}> クリックしてください。</button> 
    </div>
  )
}

export default Counter;
```

ちなみに以下の様にして複数の`state`を定義していきます。

```jsx
import React, { useState } from  'react';

function Counter() {
  const [count, setCount] = useState(0)
  const [name, setName] = useState('')

  return(
    <div>
      <p>{count} 回クリックしました</p>
      <button onClick={() => setCount(count + 1)}> クリックしてください。</button>
      <p>私の名前は{name}</p>
      <button onClick={() => setName('テスト太郎')}>名前表示</button>
    </div>
  )
}

export default Counter;
```

# Effect Hook

従来のclassコンポーネントでは`componentDidMount`や`componentDidUpdate`、`componentWillUnmount`等の中でデータ取得やDOM変更を行なっていましたが、これを`useEffect`と呼ばれるhookを使用し、関数コンポーネントでも使用可能にします。

こちらも`useEffect`の使用方法を従来の`classコンポーネント`と比較して確認していきます。

### 従来のclassコンポーネント
従来は`componentDidMount`はマウントされた直後に1回だけ呼ばれ、`componentDidUpdate`はコンポーネントが更新された後に呼ばれ、ここでデータの取得等を行いました。

![output3](https://user-images.githubusercontent.com/37989236/53772344-70c9e780-3f29-11e9-93b7-fa15cc43d4f0.gif)

```jsx
import React from  'react';

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

  componentDidMount() {
    console.log('マウントされました。')
  }

  componentDidUpdate() {
    console.log('アップデートされました。')
  }

  render() {
    return (
      <div>
        <h1>{this.state.count} 回クリックしました。</h1>
        <button onClick={() => this.setState({ count: this.state.count + 1 })}>
          クリックしてください。
        </button>
      </div>
    );
  }
}
```

### EffectHook

`useEffect`は従来の`componentDidMount`、`componentDidUpdate`、`componentWillUnmount`の３つを組み合わせた様なもので、基本的にrenderされる毎に呼ばれます。(`first render`を含む。)
`hooks`を使用した開発ではここで`side effects`を実行します。

![output4](https://user-images.githubusercontent.com/37989236/53772353-79bab900-3f29-11e9-8b36-d583c8b3456e.gif)

```jsx
import React, { useState, useEffect } from 'react'

function Effect() {
  const [count, setCount] = useState(0)

  useEffect(() => {
    console.log('レンダーされました。')
  })

  return(
    <div>
      <h1>{count} 回クリックしました</h1>
      <button onClick={() => setCount(count + 1)}> クリックしてください。</button>
    </div>
  );
}
```

# Custom Hooks
上記で記載した通り、共通のロジックをコンポーネント間での再利用を可能にします。

以下の2つのコンポーネントがあるとします。

- (1) 受け取った`id`が`1`だったら`ログイン中です`を返す、`status.js`、
- (2) 受け取った`id`が`1`だったら`おかえりなさい`を返す`message.js`。


```jsx:status.js
export default function Status(props){
  const [isLoggedIn, setIsLoggedIn] = useState(false);

  const handleStateChange = (id) => {
    if(id === 1){
      setIsLoggedIn(true)
    }
    else{
      setIsLoggedIn(false)
    }
  }

  useEffect(() => {
    handleStateChange(props.user.id)
  })

 const status = isLoggedIn ? 'ログイン中' : 'サインアップ'

  return (
    <>
      <h1>Status: {status}</h1>
    </>
  )
}
```

```jsx:message.js
export default function Message(props){
  const [isLoggedIn, setIsLoggedIn] = useState(false);

  const handleStateChange = (id) => {
    if(id === 1){
      setIsLoggedIn(true)
    }
    else{
      setIsLoggedIn(false)
    }
  }

  useEffect(() => {
    handleStateChange(props.user.id)
  })

 const message = isLoggedIn ? 'おかえりなさい' : 'あなたは誰ですか？'

  return (
    <>
      <h1>Message: {message}</h1>
    </>
  )
}
```

ここの共通したロジック部分を`custom Hook`を使用する事で、以下の様に抜き出す事ができます。
※__抜き出したロジックのコンポーネントは`use`から始まる慣習があります。今回は`useLogin`と名付けました。__

```jsx:useLogin
import { useState, useEffect } from 'react';

export default function useLogin(userId){
  const [isLoggedIn, setIsLoggedIn] = useState(false);

  // コンポーネント間で再利用したいロジック
  const handleStateChange = (id) => {
    if(id === 1){
      setIsLoggedIn(true)
    }
    else{
      setIsLoggedIn(false)
    }
  }
  
  // side effectsを実行する。
  useEffect(() => {
    handleStateChange(userId)
  })

  return isLoggedIn;
}
```

`useLogin`を使用する事で`status.js`と`message.js`をよりスッキリ書くことができます。

```jsx:user.js
import React from 'react';
import useLogin from './useLogin';

export default function Status(props){
  const status = useLogin(props.user.id) ? 'ログイン中' : 'サインアップ'
  return (
    <>
      <h1>Status: {status}</h1>
    </>
  )
}
```

```jsx:message.js
import React from 'react';
import useLogin from './useLogin';

export default function Message(props){
  const message = useLogin(props.user.id) ? 'おかえりなさい' : 'サインアップしてください'
  return (
    <>
      <h1>Message: {message}</h1>
    </>
  )
}
```

`custom hooks`では他にも色々な事ができるので、詳細は[公式ドキュメント](https://reactjs.org/docs/hooks-custom.html)で確認ください。

# 参照
`hooks`の説明としては本当にざっくりでしたので、詳細は[公式ドキュメント](https://reactjs.org/docs/hooks-intro.html)で確認ください。