基礎から学ぶReact/React Hooks学習メモ 5-6 カスタムフック

# React Hooksを基礎から理解する 5-6 カスタムフック

参考
[基礎から学ぶReact/React Hooks](https://www.amazon.co.jp/dp/B09CP8T4TX)

## カスタムフックとは

- 関数名がuseから始まる独自のフック。ほかのフックを呼び出せる関数。
- UIと切り離してロジックごとに処理を切り出すことにより、カスタムフックの使いまわしや、重複したロジックを取り除くことができる。

## カスタムフックの作成例

### ベースとなるコンポーネント

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/88686/249e9172-73cd-0c7f-d3ad-fde6acbc155e.png)

```js
import React, { useState } from "react";

const CounterText = (props) => <p>現在のカウント数: {props.count}</p>;

const INITIAL_COUNT = 0;

const Counter = () => {
  const [count, setCount] = useState(INITIAL_COUNT);
  const countAdd = () => setCount((prevCount) => prevCount + 1);
  const countSub = () => setCount((prevCount) => prevCount - 1);
  const countReset = () => setCount(INITIAL_COUNT);

  return (
    <>
      <CounterText count={count} />
      <button onClick={countAdd}>ボタン +1</button>
      <button onClick={countSub}>ボタン -1</button>
      <button onClick={countReset}>リセット</button>
    </>
  );
};

export default function App() {
  return <Counter />;
}
```

### ロジックをフックに切り出す

```js
import React, { useState } from "react";

const CounterText = (props) => <p>現在のカウント数: {props.count}</p>;

const INITIAL_COUNT = 0;

// フックを定義
const useCounter = (initialCount) => {
  const [count, setCount] = useState(initialCount);
  const countAdd = () => setCount((prevCount) => prevCount + 1);
  const countSub = () => setCount((prevCount) => prevCount - 1);
  const countReset = () => setCount(initialCount);

  return { count, countAdd, countSub, countReset };
};

const Counter = () => {
  // カスタムフックの利用
  const { count, countAdd, countSub, countReset } = useCounter(INITIAL_COUNT);

  return (
    <>
      <CounterText count={count} />
      <button onClick={countAdd}>ボタン +1</button>
      <button onClick={countSub}>ボタン -1</button>
      <button onClick={countReset}>リセット</button>
    </>
  );
};

export default function App() {
  return <Counter />;
}
```

## カスタムフックを利用する

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/88686/0c6f7da5-defa-9125-0b0d-c3fa10c89114.png)

- カウンターカスタムフック

```js:useCounter.js
import React, { useState } from "react";

export const useCounter = (initialValue) => {
  const [count, setCount] = useState(initialValue);
  const countAdd = () => setCount((prevCount) => prevCount + 1);
  const countSub = () => setCount((prevCount) => prevCount - 1);
  const countReset = () => setCount(initialValue);

  return { count, countAdd, countSub, countReset };
};
```

- 「現在のカウント数」表示コンポーネント

```js:CounterText.js
import React from "react";

export const CounterText = ({ count }) => {
  return (
    <p>
      現在のカウント数: <b>{count}</b>
    </p>
  );
};
```

- カウンター部分（タイトル、ボタン）

```js:Counter.js
import React from "react";
import { useCounter } from "./useCounter";
import { CounterText } from "./CounterText";

export const Counter = ({ counterName }) => {
  const { count, countAdd, countSub, countReset } = useCounter(0);
  return (
    <p>
      <h1>{counterName}</h1>
      <CounterText count={count} />
      <button onClick={countAdd}>ボタン +1</button>
      <button onClick={countSub}>ボタン -1</button>
      <button onClick={countReset}>リセット</button>
    </p>
  );
};
```

- 全体

```js:App.js
import { Counter } from "./Counter";
import "./styles.css";

export default function App() {
  return (
    <div>
      <Counter counterName="カウンターA" />
      <Counter counterName="カウンターB" />
      <Counter counterName="カウンターC" />
    </div>
  );
}
```