Simple yet powerful solution for debounced state in react. This hook is based on the standard react hook useState. useStateDebounced provides a similar functionality. It returns the same array of [value, setValue] plus debounced value.
useStateDebounced hook
function useStateDebounced(delay, initialState)) {
const [value, setValue] = useState(initialState);
const [debouncedValue, setDebouncedValue] = useState(value);
useEffect(() => {
const timer = setTimeout(
() => setDebouncedValue(value),
delay
);
return () => {
clearTimeout(timer);
};
}, [value, delay]);
return [value, debouncedValue, setValue];
}
Usage
Usually we need debounced state to delay some costly operation execution until user interaction finished. In this example we wait for the user to finish typing in the search dialog before fetching a new list of recipes. So 700 ms after the last user's keystroke debouncedTerm
is updated and the server query is executed.
import React, { useEffect, useState } from 'react';
import { useStateDebounced } from 'use-state-debounced';
export const RecipesList = () => {
const [recipes, setRecipes] = useState([]);
const [term, debouncedTerm, setTerm] = useStateDebounced(700, 'pizza');
useEffect(() => {
const filteredList = await fetchRecepiesFromServer(debouncedTerm);
setRecipes(filteredList);
}, [debouncedTerm]);
return (
<>
<input value={term} onChange={e => setTerm(e.target.value)} />
<ul>
{recipes.map((r) =>
(<li key={r.id}>{r.name}</li>)
)}
</ul>
</>
);
};
In the above example we use <input>
as a controlled component. For uncontrolled components the first term
parameter can be omitted.
const [, debouncedTerm, setTerm] = useStateDebounced(700);
<input onChange={e => setTerm(e.target.value)} />
TypeScript version of useStateDebounced can be found here.
Top comments (0)