LoginSignup
2

More than 3 years have passed since last update.

【React】おなじみのカウンターをカスタムフック化してみた

Last updated at Posted at 2020-01-19

概要

おなじみのカウンターアプリをカスタムフックとしてコンポーネントから処理を切り出してみたので共有しておきます。

ソース

CodeSandBox

Counterコンポーネント

Counter.tsx
import React from "react";
import useCounter from "../customHooks/useCounter";

type CounterProps = {
  minCount: number;
  maxCount: number;
};

function Counter(props: CounterProps) {
  const { minCount, maxCount } = props;

  const { count, addCount, message: countMessage, resetCount } = useCounter({
    minCount: minCount,
    maxCount: maxCount,
    initMessage: "初期値"
  });

  return (
    <div>
      <div style={{ fontSize: 12 }}>
        ({minCount} ~ {maxCount})
      </div>
      <div>COUNT: {count}</div>
      <div>MESSAGE: {countMessage}</div>
      <div>
        <button
          onClick={() => {
            addCount(1);
          }}
        >
          {" +1 "}
        </button>
        <button
          onClick={() => {
            addCount(-1);
          }}
        >
          {" -1 "}
        </button>
        <button
          onClick={() => {
            resetCount();
          }}
        >
          RESET
        </button>
      </div>
    </div>
  );
}

export default Counter;

useCounter

useCounter.tsx
import React, { useState } from "react";

type UseCounterProps = {
  initCount?: number;
  initMessage?: string;
  minCount?: number;
  maxCount?: number;
};

type UseCounterReturn = {
  count: number;
  addCount: (value: number) => void;
  message: string;
  resetCount: () => void;
};

function useCounter({
  initCount = 5,
  initMessage = "",
  minCount = 0,
  maxCount = 10
}: UseCounterProps): UseCounterReturn {
  const [count, setCount] = useState<number>(initCount);
  const [message, setMessage] = useState<string>(initMessage);

  const addCount = (value: number) => {
    const nextCount = count + value;
    if (nextCount < minCount) {
      setMessage("最小値を下回ります");
    } else if (nextCount > maxCount) {
      setMessage("最大値を上回ります");
    } else {
      setMessage("成功");
      setCount(prev => prev + value);
    }
  };

  const resetCount = () => {
    setMessage("カウントリセット");
    setCount(initCount);
  };

  return { count, addCount, message, resetCount };
}

export default useCounter;

カスタムフックって?

簡単な話、カスタムフックはただの関数コンポーネントで、hooksを利用し状態(state)や副作用(effect)を持つこともでき、使いまわすことも出来る。ただ、DOMを返す代わりにインターフェースを提供する、それだけの事です。コードが抽象化されるのはもちろん、カプセル化のような効果もあり、保守性があがります。

カウンターは何が起きてる?

useCountercount(カウントの値) addCount(カウント操作) message(結果メッセージ) resetCount(カウントリセット)を提供し、Counterコンポーネントでは提供された値とインターフェースを利用して表示させています。

ここでインスタンスが生成されます。

Counter.tsx_抜粋
const { count, addCount, message: countMessage, resetCount } = useCounter({
  minCount: minCount,
  maxCount: maxCount,
  initMessage: "初期値"
});

ボタンがおされると、useCounterの提供しているaddCount()が走ります。

Counter.tsx_抜粋
<button
  onClick={() => {
    addCount(1);
  }}
>
  {" +1 "}
</button>

useCounterのaddCount()が実行され、状態が更新されます。

useCounter.tsx_抜粋
const addCount = (value: number) => {
  const nextCount = count + value;
  if (nextCount < minCount) {
    setMessage("最小値を下回ります");
  } else if (nextCount > maxCount) {
    setMessage("最大値を上回ります");
  } else {
    setMessage("成功");
    setCount(prev => prev + value);
  }
};

伴いCounterのビューも更新されます。

Counter.tsx_抜粋
<div>COUNT: {count}</div>
<div>MESSAGE: {countMessage}</div>

まだまだ初心者なので、ツッコミどころがあればご指摘お願いします。

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
2