React - FunctionalComponent  vs  ClassComponent

# Componentとは
- Componentはユーザーインターフェイスの一部を表します。
- Componentは再利用可能で、ユーザーインターフェイスのどこでも使用できます。

- Reactには主に2つのコンポーネントタイプがあります。
   - Class Component
   - Functional Component

# Functional ComponentとClass Componentの比較
## Syntax
### Class Component
- React.Componentというクラスから継続するクラスです。
- React要素を返却するrenderというメソッドでhtmlUIを定義します。

```javascript
class Index extend React.Component {
    render() {
        return(
            <div>FunctionComponent</div>
        )
    }
}
```

### Functional Component
-  html UIを返却する単純なJavaScript関数です。
-  arrow functionを使用して定義できますが、通常の`function`キーワードも良いです。
-  propsを引数として受け入れてReact要素を返します。
-  renderメソッドがないです。

```javascript
const Index = () =>  {
    return(
        <div>FunctionComponent</div>
    )
}
```

## Lifecycle
### Class Component
3つのフェーズがあります。

- Mounting
Mountingとは、要素をDOMに配置することです。
こちらのフェーズで、下記の順序で呼び出される4つの組み込みメソッドがあります。
    1. constructor()
    2. getDerivedStateFromProps()
    3. render()
    4. componentDidMount()

- Updating
ComponentのStateまたはPropsに変更するたびに、Componentが更新されることです。
こちらのフェーズで、下記の順序で呼び出される5つの組み込みメソッドがあります。
    1. getDerivedStateFromProps()
    2. shouldComponentUpdate()
    3. render()
    4. getSnapshotBeforeUpdate()
    5. componentDidUpdate()

- Unmounting
Unmountingとは、要素をDOMから削除されることです。
こちらのフェーズで一つの組み込みメソッドだけがあります。
    1. componentWillUnmount()

参考：https://www.w3schools.com/react/react_lifecycle.asp
### Function Component
- 単純なJavaScript関数なので、Component lifecycleメソッドが存在しなくてsetStateも使えないので、Function ComponentはStateLessを呼ばれます。
- Lifecycleを管理するため、ReactHooksを使用できます。
- useEffectを使用してLifecycleの動作を複製でき、useStateを使用してStateを管理できます。
- ClassComponentの三つのフェーズでは必ず必要なメソッドは、
    - componentDidMount() =>  **要素をDOMに配置した時の処理**
    - componentDidUpdate() => **Componentを更新された時の処理**
    - componentWillUnmount() => **要素をDOMから削除された時の処理**

上記の三つのメソッドは、useEffectだけを使用して対応できます。

```javascript
  useEffect(() => {
    effect
    return () => {
      cleanup
    };
  }, [input]);
```

#### componentDidMountの対応
```javascript:useEffect
import React, { useEffect } from "react";

const Component = () => {
  useEffect(() => {
    console.log("Behavior before the component is added to the DOM");
  }, []);

  return <h1>Hello World</h1>;
};
```
**=>**
 
上記の例では、ComponentがマウントされるときにuseEffectが呼び出されます。 
2番目の引数として空の配列(`[]`)の場合、
Componentのマウント時に1回だけ実行する必要があります。

#### componentDidUpdate()の対応
- 2番目の引数を渡せない場合、Componentをレンダーするたびに、いつもuseEffectをトリガーされます。

```javascript:useEffect
import React, { useEffect } from "react";

const Component = () => {
  useEffect(() => {
    console.log("Behavior when the component receives new state or props.");
  });

  return <h1>Hello World</h1>;
};

```

- 2番目の引数を渡す時、引数の値を変わる時だけ、useEffectをトリガーされます。

```javascript:useEffect
import React, { useEffect } from "react";

const Component = ({ hoge }) => {
  useEffect(() => {
    console.log("Behavior when the value of 'hoge' changes.");
  }, [hoge]);

  return <h1>Hello World</h1>;
};
```

#### componentWillUnmount()の対応
- useEffectの中に`return`を定義すると、要素をDOMから削除された時、return内の処理を実行されます。

```javascript:useEffect
import React, { useEffect } from "react";

const Component = () => {
  useEffect(() => {
    return () => {
            console.log("Behavior right before the component is removed from the DOM.");
        }
  }, []);

  return <h1>Hello World</h1>;
};

```

#### 同時に対応する時
```javascript:useEffect
import React, { useEffect, useRef } from "react";

//// Mountしたかどうか確認
export const useDidMount = () => {
  const ref = useRef<boolean>();
  useEffect(() => {
    ref.current = true;
  }, []);
  return ref.current;
};


const Component = () => {
  const isDidMount = useDidMount();

  useEffect(({hoge}) => {
    if(isDidMount) {
        // <componentDidMount>
    } else {
        // <componentDidUpdate/>
    }

    // <componentWillUnmount>
    // returnがあったら、要素をDOMから削除された時、return内の処理を実行されます。
    return () => {
        console.log('componentWillUnmount');
    }
    // <componentWillUnmount/>
  }, [hoge]);

  return <h1>Hello World</h1>;
};

```

#### useStateで、Stateを管理する

``` javascript:FunctionComponent.jsx
import React, { useState } from "react";

const FunctionComponent = () => {
  const [value, setValueMethod] = useState("default_value");
  return (
    <input value={value} onChange={(event) => setValueMethod(event.target.value)} />
  );
};

export default FunctionComponent;
```

- ClassComponentで同じ意味のコードです。

```javascript:ClassComponent.jsx
import React from "react";

class ClassComponent extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      value: "default_value"
    };
  }
  render() {
    return (
      <input
        value={this.state.value}
        onChange={(event) => this.setState({ value: event.target.value })}
      />
    );
  }
}
export default ClassComponent;

```

# なぜFunctionalComponentを使った方が良い？
- Javascriptメソッドなので、クラスより、コードを読みやすくて、テストしやすいです。
- クラスよりコードが少ないです。
- メソッドなのでScopeを管理しやすいです。クラスだと、いつもFunctionを呼ぶ時、いつも`this`(componentのScopeを確定する必要です。（例：this.handle.bind(this)）
- Lifecycleをもっと管理しやすいです。