3
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

こぼのフロントエンドレビュー帳Advent Calendar 2022

Day 2

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

Last updated at Posted at 2022-12-01

はじめに

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

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

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

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

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

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

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

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

カスタムフックを使わないパターン
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>
    </>
  );
};

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

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 };
};
カスタムフックを使ったパターン
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のあるカウンターアプリ

カスタムフックを使わないパターン
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>
    </>
  );
};

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

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

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 };
};
カスタムフックを使ったパターン
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>
    </>
  );
};

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

まとめ

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

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

上記はまたの機会に

3
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?