useCallbackについて学んできたZE★

## これはなに？
React初学者の私がフロントエンドになるための第一弾！
この記事では、Reactのhooksである`useCallback`について学んできました！

## とりあえず、`useCallback`ってなんなん？

`useCallback`ってなんなんということですが...
　👉結論: **パフォーマンス向上のためのhooks**です！
**ありがとうございました！！**
と、いきたいところなのですが、詳細書いていきたいと思います。

useCallbackとは、**関数をメモ化**することができます。

メモ化とは、いわばキャッシュです。(多分)
Reactでは、親コンポーネントの再描画によって、
変更のない子コンポーネントまで再描画されてしまうことがしばしばあります。

そんな時に使うのが、`useCallback`です。

では、関数をメモ化するとはいったいどういうことなのでしょう。

## 関数をメモ化するとは？

まず、サンプルとして以下のコードを見てみましょう。

```js:Parent.js
const updateCountA1 = () => {
  setCountA((prev) => prev + 1);
};

const updateCountA2 = () => {
  setCountA((prev) => prev + 1);
};

Object.is(updateCountA1, updateCountA2)
```

上記の場合、`Object.is()`の返り値は何になるでしょう。
一見、`updateCountA1`と`updateCountA2`は、
まったく同一の処理を行なっているため、`true`が返ってくるように思えます。
が、実際の返り値は`false`となり、異なるオブジェクトとして判定されます。

これでは、コンポーネントが描画される度に関数が定義されてしまい、パフォーマンスの悪化に繋がります。
そこで活躍するのが、今回の`useCallback`となるわけです。

では、早速useCallbackの書き方を見ていきましょう。

### `useCallback`の書き方
ここでは、`onClick`などで使う関数を想定してみます。

```js:Parent.js
import { useCallback } from 'react'
~~~
const handleClick = useCallback(() => {
	doSomething(a, b);
},[a, b]);
```

:::note info
useCallbackはhooksなので`react`から`import`が必要です。
:::

では関数の構成を見ていきましょう。

```js:Parent.js
const handleClick = useCallback(() => {
    //第一引数 コールバック関数
	doSomething(a, b);
  },
//第二引数 依存配列
[a, b]);
```

useCallbackは以下のような構成になっています。

#### 第一引数 コールバック関数
第一引数には実行したい関数を記述します。
今回の例でいえば`onClick`で実行する関数にあたります。
`doSomething(a, b)`の関数が実行されます。

#### 第二引数 依存配列
第二引数には依存配列を記述します。

##### 依存配列が空にする場合
依存配列は`[]`のように空にすることも可能です。


```js:Parent.js
const Parent = () => {
  const [countA, setCountA] = useState(0);

  const updateCountA = useCallback(() => {
    setCountA(countA + 1);
  }, []);

  return (
    <div>
      <button onClick={updateCountA}>countup A</button>
      <p>A: {countA}></p>
    </div>
  );
};
```

:::note alert
依存配列を空にした場合は、初回実行時に関数が定義されます。
:::

この場合、`updateCountA`内の`countA`の値は初回実行時の`1`の値でメモ化されるため、
何度`updateCountA`の関数を実行しても、`countA`の値は`1`のままとなります。

##### 依存配列に値を入れる場合
```js:parent.js
const Parent = () => {
  const [countA, setCountA] = useState(0);

  const updateCountA = useCallback(() => {
    setCountA(countA + 1);
  }, [countA]);

  return (
    <div>
      <button onClick={updateCountA}>countup A</button>
      <p>A: {countA}></p>
    </div>
  );
};
```
:::note info
依存配列に格納されている値が変化した場合のみ、関数が再定義されます。
:::

この場合、依存配列に`countA`が格納されているため、`countA`の値が更新されるたびに、
`updateCountA`の関数は再定義されます。
そのため、`countA`の値はカウンターの役目を果たすことができます。





## 実際に使ってみるZE★
### `useCallback`を使わない場合
```js:Parent.js
import React, { useCallback, useState } from "react";
import Child from "./Child";

const Parent = () => {
  console.log("親コンポーネントrendar");

  const [countA, setCountA] = useState(0);
  const [countB, setCountB] = useState(0);

  const updateCountA = () => {
    setCountA((prev) => prev + 1);
  };

  const updateCountB = () => {
    setCountB(countB + 1);
  };

  return (
    <div>
      <button onClick={updateCountA}>countup A</button>
      <Child onClick={updateCountB} />
      <p>A: {countA}</p>
      <p>B: {countB}</p>
    </div>
  );
};
```

```js:Child.js
import React, { useCallback, useState } from "react";
import Child from "./Child";

const Parent = () => {
import React from "react";

const Child = React.memo(({ onClick }) => {
  console.log("子コンポーネントrendar");
  return (
    <div className="childComponent">
      <button onClick={onClick}>countup B</button>
    </div>
  );
});
```
:::note alert
この場合、`setCountA`が実行された場合でも、
子コンポーネントである`Child.js`が再描画されてしまいます。
:::

### `useCallback`を使う場合
```js:Parent.js
import React, { useCallback, useState } from "react";
import Child from "./Child";

const Parent = () => {
  console.log("親コンポーネントrendar");

  const [countA, setCountA] = useState(0);
  const [countB, setCountB] = useState(0);

  const updateCountA = () => {
    setCountA((prev) => prev + 1);
  };

  // 先ほどのコードから変更はuseCallbackのみ
  const updateCountB = useCallback(() => {
    setCountB(countB + 1);
  }, [countB]);

  return (
    <div>
      <button onClick={updateCountA}>countup A</button>
      <Child onClick={updateCountB} />
      <p>A: {countA}</p>
      <p>B: {countB}</p>
    </div>
  );
};
```

```js:Child.js
import React, { useCallback, useState } from "react";
import Child from "./Child";

const Parent = () => {
import React from "react";

const Child = React.memo(({ onClick }) => {
  console.log("子コンポーネントrendar");
  return (
    <div className="childComponent">
      <button onClick={onClick}>countup B</button>
    </div>
  );
});
```

:::note info
`useCallback`を使うことで、`setCountA`が実行された場合でも、
子コンポーネントである`Child.js`は再描画されなくなります。
:::

## まとめ
### `useCallback`とは...？のまとめ
* 関数をメモ化することができる
* メモ化することで不要なレンダリングを防ぐことができる
* パフォーマンスを向上させることができる

### `useCallback`の使い方のまとめ
* 第一引数にはコールバック関数を記述する
* 第二引数には依存配列を記載する
    * 依存配列は`[]`でもOK
        * ただし関数が定義されるのは初回実行時のみ
    * 依存配列に値を格納することができる
        * 格納された値が更新される度に関数が再定義される


では、良きReactライフを！！