概要
おなじみのカウンターアプリをカスタムフックとしてコンポーネントから処理を切り出してみたので共有しておきます。
ソース
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を返す代わりにインターフェースを提供する、それだけの事です。コードが抽象化されるのはもちろん、カプセル化のような効果もあり、保守性があがります。
カウンターは何が起きてる?
useCounter
はcount
(カウントの値) 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>
〆
まだまだ初心者なので、ツッコミどころがあればご指摘お願いします。