Problem
When you need to implement a real-time search form, you can just do that by firing a specific function on the onChange event. But if you are to call API, that’s not really good practice because you end up calling API so many times unnecessarily.
Solution
To avoid that problem, we better execute a function in proper timing which means after a user stops typing for a while. And setTimeout helps us to do that.
setTimeout(function, milliseconds, param1, param2, …)
The setTimeout() method calls a function or evaluates an expression after a specified number of milliseconds.
The way it works is that a timer is set to execute the function after xx seconds (let’s say 0.5 seconds) each time the user types a character, and when the next character is typed, the previously set timer is canceled and a new timer is set. In this way, the function is only executed 0.5 seconds after the end of the user’s continuous input.
Code
1. With 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 works each time the variables are updated specified in the second argument. Using this, keep resetting a timer.
2. Without 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>
)
}
Without useEffect is a bit more straightforward. And it doesn’t fire unnecessarily on the first render.