useDebouncedState
Debounces state changes of un-controlled components. This can be useful in case you want to perform a heavy operation based on react state, for example, send a search request.
Differences with useDeferredValue
useDeferredValue
(opens in a new tab) is a new React built-in hook introduced in React 18. It has very different usages and goals than useDebouncedState
:
useDeferredValue
can only be used if you have direct access to the original state value, whileuseDebouncedState
is designed to work when you don't have access to the original state value.useDeferredValue
can suppress Suspense fallback from re-appearing when the value changes, which makes it useful in Suspense-based data fetching.useDeferredValue
is better suited to optimizing rendering because it is deeply integrated with React itself and adapts to the user’s device as it doesn’t require choosing any fixed delay. The deferred re-render would happen almost immediately and wouldn’t be noticeable if the user’s device is fast (e.g. powerful laptop), while the re-render could “lag behind” the user interaction proportionally to how slow the device is.useDeferredValue
are interruptible by default, e.g. if React is in the middle of re-rendering a large list, but the user makes another input, React will abandon the current re-render, handle the keystroke, and then start rendering in the background again. WhileuseDebouncedValue
is not interruptible and wouldn’t improve the "lagging" issue.useDeferredValue
can not reduce network requests. Though the re-render triggered by theuseDeferredValue
can be interrupted by user interaction, the returned JSX from the re-render can be discarded by React (due to being outdated during Concurrent Rendering), the re-render itself will always happen and the network request will always be fired.
Differences with useDebouncedValue
useDebouncedValue
is another hook provided by foxact. However, it is designed to work with controlled components:
useDebouncedState
is used for un-controlled components (ThedefaultValue
prop and theonChange
prop, novalue
prop)- With
useDebouncedState
you can not have direct access to the original state value.
Usage
Below is an example of different use cases of useDebouncedState
and useDeferredValue
, and how they can be used together:
import { useDeferredValue } from 'react';
import useSWR from 'swr';
import { useDebouncedState } from 'foxact/use-debounced-state';
const Example = () => {
const [debouncedValue, debouncilySetState] = useDebouncedState(
// The initial value or a pure function that will return the initial value, just like the useState
initialValue,
// delay in ms
300,
// optional, default to false. whether to immediately update the debounced value with the first call
false
);
// The debounced value can reduce network requests.
const { data } = useSWR<string[]>(debouncedValue ? `/api/search?q=${debouncedValue}` : null);
// useDeferredValue here is used to opt-in the Concurrent Rendering, to improve the UX.
// The value passed to useDeferredValue must be primitive values or memoized. Here we
// are relying on useSWR to memoize the returned `data` (which will be an array).
const deferredData = useDeferredValue(data);
return (
<div>
<input
// The <input /> here is not controlled by React as we are not using the `value` prop.
defaultValue={initialValue}
// Although the `onChange` will be fired on every keystroke, the state update will be
// debounced
onChange={useCallback((e) => debouncilySetState(e.target.value), [debouncilySetState])}
/>
{/**
* <FancyYetSlowSearchResult /> needs to be wrapped in React.memo, so that it will
* only re-render when the `deferredData` changes, not when the `debouncedValue` changes.
*/}
<FancyYetSlowSearchResult
// The re-render of <FancyYetSlowSearchResult /> will be interruptible, as it will
// be triggered by `useDeferredValue`.
// So <FancyYetSlowSearchResult /> may be slow to render, the entire UI will always
// remain responsive.
list={deferredData}
/>
</div>
);
}