連続する呼び出しを無視してくれるDebounce機能を実現したhook
import React, {Fragment, useEffect, useState} from 'react';
const MySearch = () => {
const [inputVal, setInputVal] = useState('')
const handleInputChange = (event) => {
setInputVal(event.target.value)
}
/**
* useDebounceカスタムフック
* @param val
* @param delay ミリ秒
*/
const useDebounce = (val, delay) => {
const [debouncedVal, setDebouncedVal] = useState(val)
// Note:useEffect()第 2 引数を指定しないと、毎回のコンポーネントのレンダー後に、第1引数を
// 実行する
useEffect(() => {
const timeout = setTimeout(() => setDebouncedVal(val), delay)
// useEffectの第1引数を実行する前に、前回のuseEffectでreturnされたfunction
// を実行する
return () => clearTimeout(timeout)
}, [val, delay])
return debouncedVal
}
// キーワード入力して、2秒以上待てば、サーベーに送信する
const debouncedVal = useDebounce(inputVal, 2000)
useEffect(() => {
// 省略:キーワード(debouncedVal)をサーベーに送信して、検索を行う
// 以下はDebug用
const time = new Date();
const nowTime = time.getHours() + "時" + time.getMinutes() + "分" + time.getSeconds() + "秒";
console.log(nowTime, ':debouncedVal:', debouncedVal)
}, [debouncedVal])
return (
<Fragment>
{/*検索語を入力すると、サーバーと通信して、検索を行う*/}
入力欄:<input onChange={handleInputChange} value={inputVal}/>
</Fragment>
)
}
export default MySearch
ノーマルバージョンのDebounce機能を実現したfunction
const debounce = (cb, delay) => {
// ポイントはClosureを利用すること
let timeout
return () => {
if (timeout) {
clearTimeout(timeout)
}
timeout = setTimeout(function () {
cb()
}, delay)
}
}
const debouncedFunc = debounce(() => console.log('call'), 2000)
// 下記のコードは同期ですので、一瞬的に実行完了する。Debounce Functionで飾るので、コンソール
// で「'call'」を一つしか表示しない。
debouncedFunc() // #1
debouncedFunc() // #2
debouncedFunc() // #3
// 「timeout#1」は#1を実行する時のtimeout
// #1を実行する時、timeoutはundefined、「if (timeout)」はfalse,timeout#1に値を代入する
// #2を実行する時、「if (timeout)」はtrue、timeoutはclearTimeoutされた,timeout#2に値を代
// 入する
// #3を実行する時、「if (timeout)」はtrue、timeoutはclearTimeoutされた,timeout#3に値を代
// 入する
// 最後はtimeout#3をclearTimeoutされず、残った