はじめに
今回は、react nativeで開発をした際に使用していた連打対策のためのカスタムフックを紹介します。
背景
画面遷移を行うボタンを連打すると同じページが2回開いてしまうなど、連打できることで問題が発生してしまうコンポーネントがいくつかありました。
また、連打対策をする必要のあるコンポーネントが多数存在したので、利用しやすいカスタムフックで作成しました。
実装
import { useRef } from 'react';
export const useDebounce = () => {
const canPress = useRef<boolean>(true);
const debounce = (onPress: Function, duration: number = 1000) => {
setTimeout(() => {
canPress.current = true;
}, duration);
if (canPress.current) {
canPress.current = false;
onPress();
}
};
return { debounce };
};
使用例
以下のように、hooksから返されるdebounce()
で関数をラップすることで、簡単に連打対策が実現できます。
const Button: FC = () => {
const { debounce } = useDebounce();
const handleClick = () => {
console.log('clicked');
};
return (
<button
onClick={() => debounce(handleClick)} // 連打しても初回クリックから1秒間は無効
>
Click
</button>
);
};
debounce(handleClick, 2000)
のように、第2引数に任意の秒数(ms単位)を指定することもできます。
解説
簡単な実装ではありますが、一応解説です。
useDebounce
はcanPress
というRefを持っています。初期値はtrueです。
useRefについてわからないって方はぜひ公式のリファレンスをご覧ください!
<button
onClick={() => debounce(handleClick)}
>
上記のような実装をしたとき、onClickが発火するとsetTimeout
が走ります。
setTimeout(() => {
canPress.current = true;
}, duration);
durationに設定した時間がたった後(デフォルトでは1000ms=1秒後)、canPress.current
にtrueをセットします。
その後以下のようなコードが続きます。
if (canPress.current) {
canPress.current = false;
onPress();
}
canPress.current
がtrueの時、if文の中身を実行しています。
canPress.current
にfalseをセットし、引数のonPressを実行します。
このような実装をすることによって、
-
初回ボタンクリック時に引数のonPressを実行しつつ
canPress.current
をfalseに。1秒後にcanPress.current
をtrueに戻すタイマーもセット -
1秒経過する前にクリックされると、
canPress.current
がfalseであるためif文で弾かれてonPressは実行されない -
1秒経過すると
canPress.current
をtrueに戻すタイマーが作動し、再度クリックでonPressが発火するようになる
という動作が実現できます。
おわりに
最後までお読みいただきありがとうございました!
もっといい方法をご存知の方はコメントで教えてくださると嬉しいです🙇♂️