Why doesn't my debounce function work in a React app with hooks?
rookie
My goal is to trigger a fetch request to fetch data from the API after some delay. In my particular case, I have an input field where the user can enter the post ID. I don't want to trigger a fetch request on every number entered in the input field. I only want to make the request 1 second after the user has stopped entering data. Here is my implementation:
import { useCallback, useEffect, useState } from 'react'
import './App.css'
function debounce(fn, ms) {
let timeoutId
return function (...args) {
if (timeoutId) clearTimeout(timeoutId)
timeoutId = setTimeout(() => {
fn(...args)
}, ms)
}
}
function App() {
const [input, setInput] = useState('')
const fetchData = async () => {
if (input !== '') {
let res = await fetch(`https://jsonplaceholder.typicode.com/posts/${input}`)
let resData = await res.json()
console.log(resData)
}
}
const fireRequest = useCallback(debounce(fetchData, 1000), [])
useEffect(() => {
fireRequest()
}, [input])
return (
<div className='App'>
<input type='text' onChange={(e) => setInput(e.target.value)} value={input}></input>
</div>
)
}
export default App
For some reason it doesn't work. There are no errors, and it doesn't appear to be getting my data (no logging whatsoever to the console). What am I doing wrong? thanks.
Rajat Jain
The main problem here is that the function is only called when input != ""
. The function does not become a no-op until the input is not set to the desired value. However, this change will help
import { useCallback, useEffect, useState } from 'react'
import './App.css'
function debounce(fn, ms) {
let timeoutId
return function (...args) {
if (timeoutId) clearTimeout(timeoutId)
timeoutId = setTimeout(() => {
fn(...args)
}, ms)
}
}
export default function App() {
const [input, setInput] = useState('')
const handleInputChange = (e) => {
setInput(e.target.value);
debouncedFireRequest(e.target.value);
};
const debouncedFireRequest = useCallback(
debounce(async (value) => {
if (value !== '') {
let res = await fetch(`https://jsonplaceholder.typicode.com/posts/${value}`)
let resData = await res.json()
console.log(resData)
}
}, 1000),
[]
);
return (
<div className='App'>
<input type='text' onChange={handleInputChange} value={input}></input>
</div>
);
}