React Hooksって結局いつ使うの？

## 導入
最近、React Hooksについて勉強しているのですが、どんなことができるのかなんとなく分かってもどういうメリットがあるのかイマイチ分からないということがあります

そこで今回はReact Hooksを使うとどんなメリットがあるのかをいろいろと調べてみたので学習記録という意味でもまとめてみようと思います

## まず最初に：useStateとレンダリングの仕組み
useStateはstateとそのstateに値を入れるsetStateの組を生成します

```javascript
const [state, setState] = useState(null);
setState('test'); // stateに'test'が入る
```

なぜuseStateを使うかを理解するにはレンダリングの流れを理解する必要があります。
以下のコードを例に解説します

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

export const Page = () => {
  const [text, setText] = useState(null);
  if(!text) {
    setText('test');
    console.log(text);
  }
  console.log(text);
  return (
    <div className="Page">
       {text}
    </div>
  );
}
```

こちらのコードを実行すると画面にはtestとだけ表示されます
以下実行の流れを見ていきます

```javascript
const [text, setText] = useState(null);
```
まず最初のuseStateでtextとsetTextを定義します。このときtextにはnullが入っています

```javascript
if(!text) {
  setText('test');
  console.log(text);
}
console.log(text);
```
textがnullならtextにtestを入れます。textは最初nullなのでここを通り、textには'test'が入ります。
ここで注意しなければならないのはsetTextはすぐに機能しないということです。setTextはtextの値を【__次のレンダリングから__】testに変更することを意味していますなのでこの時点ではtextの値は変わっておらずconsoleではどちらもnullが表示されます

```javascript
return (
  <div className="Page">
     {text}
  </div>
);
```
その状態で一度returnされます。したがって一回目のレンダリングでは何も表示されません。setTextによりtextが変更されたのでそのまますぐに２回目のレンダリングがtext=testとして実行されます

２回目のレンダリングではtextはnullではないのでsetTextは呼ばれず、そのままtext='test'が出力されます

## useStateで実現できること
useStateで実現できるのは
__画面内でのアクションによる変化を画面に反映させること__
です

こちらも例を見てみます

```javascript
export const Page = () => {
  let text = null
  if(!text) {
    text = 'test';
    console.log(text);
  }
  console.log(text);
  return (
    <div className="Page">
      <button onClick={() => {text = 'clicked'}}>button</button>
      <div>{text}</div>
    </div>
  );
}
```
ボタンをクリックすると表示される内容を変えるという内容ですが、これだと再レンダリングされないため、いくらボタンを押しても表示されるのはtestのまま変わりません
ボタンを押したことを画面に反映させるにはuseStateを使わなければなりません。

```javascript
export const Page = () => {
  const [text, setText] = useState(null);
  if(!text) {
    setText('test');
    console.log(text);
  }
  console.log(text);
  return (
    <div className="Page">
      <button onClick={() => {setText('clicked')}}>button</button>
      <div>{text}</div>
    </div>
  );
}
```
こちらのコードを使うとちゃんと表示されるtextが変化します。

なお、変更内容を画面に表示しなくてよければuseStateは必要ありません。

```javascript
export const Page = () => {
  let text = null
  if(!text) {
    text = 'test';
    console.log(text);
  }
  console.log(text);
  return (
    <div className="Page">
      <button onClick={() => {text = 'clicked'}}>button</button>
      <button onClick={() => {console.log(text)}}>display</button>
      <div>{text}</div>
    </div>
  );
}
```
このコードで一度buttonを押してからdisplayを押すとconsoleにはpushedが出力されます

## useEffectで実現できること
useEffectによって
__一部に依存した処理の不要な呼び出しを防ぐこと__
ができます

useEffectは

```javascript

useEffect(
  (), //関数
  [] //依存する変数
)
```
という形で依存する変数が変化したときのみ関数処理を行うことができます

useEffectを使わないとこのようなコードになります

```javascript
export const Page = () => {
  const [clicked, setClicked] = useState(false);
  const [text, setText] = useState(null);
  if(clicked && !text) {
    setText('test');
    console.log(text);
  }
  console.log(text);
  return (
    <div className="Page">
      <button onClick={() => {setClicked(true)}}>button</button>
      <button onClick={() => {setText(null)}}>clear</button>
      <div>{text}</div>
    </div>
  );
}
```
こちらのコードではbuttonを押すとtextにtestが入ります。
しかし、clearを押してtextをnullにしたときもif文の中に入ってしまい、そこでtextに値が入ってしまうためclearの方は上手く動きません。

useEffectを用いるとこのように書けます

```javascript
export const Page = () => {
  const [clicked, setClicked] = useState(false);
  const [text, setText] = useState(null);
  useEffect(
    () => {
      if(clicked) {
        setText('test');
        console.log(text);
      }
    },
    [clicked]
  )
  console.log(text);
  return (
    <div className="Page">
      <button onClick={() => {setClicked(true)}}>button</button>
      <button onClick={() => {setText(null)}}>clear</button>
      <div>{text}</div>
    </div>
  );
}
```
こちらではclearを押してもtextは変わっていないためuseEffectの中は呼ばれず、textの値も変わりません。
値の変化に連動してstateを変化させる処理はuseEffectを使わないと複雑になりがちなので複数の値を連動させて変化されるときはuseEffectを使うのが良いと思われます

## memo, useCallbackでできること
memoは
__一部に依存したコンポーネントの呼び出しを最小限にすること__
useCallbackは
__一部に依存したfunctionの呼び出しを最小限にすること__
ができます

役割が似ていることもあり、この２つは一緒に使われることが多いです

useCallbackは

```javascript
const functionA = useCallback(
  (), //関数
  [] //依存する変数
)
```
という形で書くことができ、このようにするとfunctionAは依存する変数が変化しない限り再生成されず、同じ関数を使い回すことができます。

memoも同様で

```javascript
const ComponentA = memo((props) => {
  // コンポーネントの内容
})
```
と書くことができ、propsの内容が変わらない限り再レンダリングされず、同じコンポーネントを使い回すことができます。

以下のコードを例に考えてみます
(例は[こちら](https://qiita.com/soarflat/items/b9d3d17b8ab1f5dbfed2)を参考にさせていただきました)

```javascript
const Child = ({handleClick}) => {
  console.log('child render')
  return(
    <button onClick={handleClick}>child button</button>
  )
}

export const Page = () => {
  const [count, setCount] = useState(0);
  console.log('render');
  return (
    <div className="Page">
      <button onClick={() => {setCount(count + 1)}}>button</button>
      <Child handleClick={() => console.log('child')} />
      <div>{count}</div>
    </div>
  );
}
```
こちらのコードではbuttonをクリックするとsetCountが走り、それによってPageだけでなく、変化していないChildも再レンダリングされてしまいます。memoやuseCallbackを使うことでこのような不要な再レンダリングを減らすことができます

```javascript
const Child = memo((props) => {
  console.log('child render')
  return(
    <button onClick={props.handleClick}>child button</button>
  )
})

export const Page = () => {
  const [count, setCount] = useState(0);
  const handleClick = useCallback(
    () => {
      console.log('child');
    },
    []
  )
  console.log('render');
  return (
    <div className="Page">
      <button onClick={() => {setCount(count + 1)}}>button</button>
      <Child handleClick={handleClick} />
      <div>{count}</div>
    </div>
  );
}
```

このようにすることで、まずuseCallbackにより、handleClickの再生成を避けることができます。すると、memoにより、ChildはhandleClickが変化しない限り再レンダリングされないようになっているのでChildの再レンダリングも避けることができ、結果的に不要なレンダリングを減らすことができるようになります。

useCallbackはmemoと一緒に扱われることが多いので勘違いしやすいですが、効果はあくまでもfunctionの再生成を防ぐことにあるのでmemoと併用する以外にも使用される場面はあると思われます(うまい例が浮かびませんが...)
関数の再生成を防ぐならuseCallback、コンポーネントの再レンダリングを防ぐならmemoと覚えておくといいです

## まとめ
useStateは__画面内で発生した変化を画面に反映させるとき__
useEffectは__一部に依存した処理の不要な呼び出しを防ぐとき__
useCallbackは__一部に依存したfunctionの再生成を防ぐとき__
memoは__一部に依存したコンポーネントの再レンダリングを防ぐとき__

に効果がある

## 参考
https://qiita.com/ossan-engineer/items/740425a0df937a47e093
https://qiita.com/uehaj/items/99f7cd014e2c0fa1fc4e
https://qiita.com/soarflat/items/b9d3d17b8ab1f5dbfed2