Problem
ユーザーがフォームに入力すると同時に検索結果を表示するリアルタイム検索を実装する場合、onChangeイベントで入力のたびにfunctionを実行すれば問題ないが、APIなどを叩いている場合必要以上に叩いてしまうことになる。
Solution
これを防ぐにはユーザーがある程度入力し終わったであろうよきタイミングでFunctionを実行してやる必要があるが、 setTimeoutをうまく活用することでこれを実現することができる。
setTimeout(function, milliseconds, param1, param2, …)
The setTimeout() method calls a function or evaluates an expression after a specified number of milliseconds.
仕組みとしては、ユーザーが文字を入力するたびに〇〇秒後に(仮に0.5秒とする)Functionを実行するというタイマーを設定し、 次の文字が入力された際は先に設定しておいたタイマーを取り消してから新たなタイマーを設定する。 こうすることでユーザーの連続した入力が終了した0.5秒後にはじめてFunctionが実行される。
Code
1. useEffectを使う場合
import React, { useState, useEffect } from 'react'
const fakeApi = () => console.log('Api is called')
export default function App() {
const [inputValue, setInputValue] = useState('')
useEffect(() => {
const timer = setTimeout(() => {
fakeApi()
}, 500)
return () => clearTimeout(timer)
}, [inputValue])
return (
<div>
<label>Input: </label>
<input
value={inputValue}
type="text"
onChange={e => setInputValue(e.target.value)}
/>
</div>
)
}
useEffectは第二引数で指定した変数が更新されるたびに実行されるため、それを利用してinput valueが変わるたびにタイマーを設定し直している。
2. useEffect無し
import React, { useState, useEffect } from 'react'
const fakeApi = () => console.log('Api is called')
export default function App() {
const [inputValue, setInputValue] = useState('')
const [timer, setTimer] = useState(null)
const inputChanged = e => {
setInputValue(e.target.value)
clearTimeout(timer)
const newTimer = setTimeout(() => {
fakeApi()
}, 500)
setTimer(newTimer)
}
return (
<div>
<label>Input: </label>
<input value={inputValue} type="text" onChange={inputChanged} />
</div>
)
}