【React】カスタムフックに切り出すとコンポーネントの見通しがよくなるので良いよ

## はじめに

React初学者向けです。
2022年のReact開発では、hooksを用いて開発することになるかと思います。

`useState`、`useEffect`...と色々公式のhooksがあったりしますが、
今回お話しするカスタムフックというのは名の通り自分でカスタムしたhooksということですね。

今回は、カスタムフックを使うとどんなメリットがあるのかについてフォーカスを当てて書きます。

## カスタムフックのメリット

いきなり本題といきましょう。

カスタムフックの最大のメリットは**hooksのロジックをコンポーネントから切り出せること**です。

実際に見た方が早いかと思います。

とてもシンプルなカウンターコンポーネントを作ります。

```tsx:カスタムフックを使わないパターン
import React, { useState } from 'react';

export const Counter = () => {
  const [count, setCount] = useState(0);
  const increment = () => setCount((current) => current + 1);
  const decrement = () => setCount((current) => current - 1);
  return (
    <>
      <button onClick={decrement}>-1</button>
      <span>{count}</span>
      <button onClick={increment}>+1</button>
    </>
  );
};
```

これが以下のように変わります。

```tsx:use-counter.ts
import { useState } from 'react';

export const useCounter = () => {
  const [count, setCount] = useState(0);
  const increment = () => setCount((current) => current + 1);
  const decrement = () => setCount((current) => current - 1);
  return { count, increment, decrement };
};
```

```tsx:カスタムフックを使ったパターン
import React from 'react';
import { useCounter } from './use-counter';

export const Counter = () => {
  const { count, decrement, increment } = useCounter();
  return (
    <>
      <button onClick={decrement}>-1</button>
      <span>{count}</span>
      <button onClick={increment}>+1</button>
    </>
  );
};
```

ロジックをコンポーネントから分けることができました。

これだけの差分がメリットを生み出すんです。
以下でもう少し複雑なカウンターアプリを作って確かめてみます。

### min, maxのあるカウンターアプリ

```tsx:カスタムフックを使わないパターン
import React, { useState } from 'react';

const MIN = 0;
const MAX = 10;

export const Counter = () => {
  const [count, setCount] = useState(0);
  const increment = () => {
    // 1. MAX以上は上げれないように
    if (count >= MAX) return;
    setCount((current) => current + 1);
  };
  const decrement = () => {
    // 2. MIN以下には下げれないように
    if (count <= MIN) return;
    setCount((current) => current - 1);
  };
  return (
    <>
      {/* 3. MINの時はボタンがdisableになるように */}
      <button onClick={decrement} disabled={count === MIN}>
        -1
      </button>
      <span>{count}</span>
      {/* 4. MAXの時はボタンがdisableになるように */}
      <button onClick={increment} disabled={count === MAX}>
        +1
      </button>
    </>
  );
};
```

どんどん見通しが悪くなっていきますね

これがカスタムフックに分けられていると見通しがかなりよくなるかと思います

```ts:use-counter.ts
import { useState } from 'react';

type Props = {
  min: number;
  max: number;
};

export const useCounter = ({ min, max }: Props) => {
  const [count, setCount] = useState(0);
  const increment = () => {
    if (count >= max) return;
    setCount((current) => current + 1);
  };
  const decrement = () => {
    if (count <= min) return;
    setCount((current) => current - 1);
  };
  return { count, increment, decrement };
};
```

```tsx:カスタムフックを使ったパターン
import React from 'react';
import { useCounter } from './dependencies/use-counter';

const MIN = 0;
const MAX = 10;

export const Counter = () => {
  const { count, increment, decrement } = useCounter({ min: MIN, max: MAX });
  return (
    <>
      <button onClick={decrement} disabled={count === MIN}>
        -1
      </button>
      <span>{count}</span>
      <button onClick={increment} disabled={count === MAX}>
        +1
      </button>
    </>
  );
};
```

かなりコンポーネントの見通しが良くなったかと思います。

## まとめ

今回は**カスタムフックを使うとロジックをコンポーネントから切り出すことができるため、見通しが良くなるよ**という話をしました。

実は、**テスタビリティが上がる**とか、**再利用性が高まる**とか他にも色々あったりするのですが、見通しが良くなるというだけでメリットがかなり大きいのでそこにフォーカスを当ててみました。

上記はまたの機会に