Why My Debounce Functionality Is Not Working In A React App With Hooks?
My goal is to fire a fetch request to get data from an API after some delay. In my particular case, I have an input field where a user can input a post ID. I don't want fire a fetc
Solution 1:
The main issue here is that you are calling the function only when input != ""
.
Till then input is not set to the desired value and thus the function becomes a no-op.
This change will however 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>
);
}
Solution 2:
Try this:
useEffect(() => {
const apiCallTimeoutId = setTimeout(() => {
fireRequest()
}, 1000);
return () => clearTimeout(apiCallTimeoutId);
}, [input]);
1 sec after the user stops typing the request will be fired.
Solution 3:
This answer is on the right track but there's no need to keep const fireRequest = useCallback(debounce(fetchData, 1000), [])
as it seems to imply.
Just fire the timeout, then clear it in the useEffect
cleanup callback if the component rerenders:
<script type="text/babel" defer>
const {useState, useEffect} = React;
const Example = () => {
const [input, setInput] = useState("");
const [result, setResult] = useState();
const fetchData = async () => {
if (input) {
try {
const res = await fetch(`https://jsonplaceholder.typicode.com/posts/${input}`);
if (res.ok) {
setResult(await res.json());
}
}
catch (err) {
console.error(err);
}
}
}
useEffect(() => {
const timeout = setTimeout(fetchData, 1000);
return () => clearTimeout(timeout);
}, [input]);
return (
<div>
<input
placeholder="type a small number, e.g. 12"
onChange={e => setInput(e.target.value)}
value={input}
/>
{result && <div>{result.title}</div>}
</div>
);
};
ReactDOM.render(<Example />, document.body);
</script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/babel-standalone/6.26.0/babel.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.4/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.4/umd/react-dom.production.min.js"></script>
Note the try
-catch
on the fetch
call and checking res.ok
rather than throwing when res.json()
fails.
Post a Comment for "Why My Debounce Functionality Is Not Working In A React App With Hooks?"