useDeferredValue
useDeferredValue is a React Hook that returns a deferred copy of a value, allowing an expensive part of your UI to lag a moment behind a fast-changing input so the input stays responsive while heavy results catch up. You give it a value and React gives you back a version that updates at a lower priority.
Learn useDeferredValue in our free React course — an interactive lesson with runnable examples, a practice exercise and a quick recall.
Part of the free React course at LearnCodingFast — hands-on lessons with examples you run in your browser, plus practice exercises and a quick quiz.
1️⃣ The Idea: A Value That Catches Up
Call const deferred = useDeferredValue(value) . The live value updates immediately (great for the input), while deferred may briefly hold the previous value during a busy render, then catch up. Pass deferred — not value — to the heavy part.
2️⃣ Pair It With React.memo
Deferring only helps if the expensive child can skip re-rendering when its prop hasn't changed. Wrap that child in React.memo and feed it the deferred value. Now it re-renders only when the deferred value updates — not on every keystroke — which is where the smoothness comes from.
3️⃣ Showing Staleness & vs useTransition
When , a newer render is pending — dim the list to signal "catching up." The key difference from useTransition : a transition wraps the code that triggers the update (you own the setState ), while useDeferredValue wraps a value you already have — perfect when the value is a prop you can't control.
These lines build a smooth search box. Put them in the right order:
📋 Quick Reference
1. Which value do you pass to the expensive child?
The deferred value. The live value goes to the input; the lagging deferred value goes to the heavy results.
So the child skips re-rendering while the deferred prop is unchanged. Without memo it re-renders every keystroke and the lag buys you nothing.
3. useTransition vs useDeferredValue — pick one in a sentence.
Use a transition when you own the setState ; use a deferred value when you only have a value (often a prop) flowing in.
Model an expensive filter that only recomputes when the query actually changes, the way a deferred value plus memo behaves. Run it and check your output.
Practice quiz
What does useDeferredValue return?
- A debounced callback
- A memoized component
- A deferred copy of a value that updates at a lower priority, lagging behind during busy renders
- A boolean indicating loading
Answer: A deferred copy of a value that updates at a lower priority, lagging behind during busy renders. You pass it a value and get back a version that may briefly hold the previous value during a busy render, then catch up.
Which value do you pass to the expensive child component?
- The deferred value
- The live value
- Both, alternating
- Neither; you pass a ref
Answer: The deferred value. The live value goes to the fast input; the lagging deferred value goes to the heavy results so they update a beat later.
Why does useDeferredValue pair with React.memo?
- memo is required by the hook
- memo makes the value update faster
- It prevents memory leaks
- So the expensive child can skip re-rendering when its deferred prop is unchanged instead of re-rendering every keystroke
Answer: So the expensive child can skip re-rendering when its deferred prop is unchanged instead of re-rendering every keystroke. Deferring only helps if the child can skip work. Wrapping it in React.memo means it re-renders only when the deferred value actually changes.
How do you detect that results are stale (a newer render is pending)?
- Check a loading boolean
- Compare the live and deferred values: value !== deferredValue means it's catching up
- Use a setTimeout
- Read a ref count
Answer: Compare the live and deferred values: value !== deferredValue means it's catching up. When the live value differs from the deferred one, a fresher render hasn't landed yet — a common pattern is dimming the list while they differ.
Does useDeferredValue debounce with a fixed delay?
- No — it's not a timer; the lag adapts to how busy React is
- Yes, 300ms by default
- Yes, but configurable
- Only in production
Answer: No — it's not a timer; the lag adapts to how busy React is. It lets the deferred value lag during a busy render and catch up when React has spare time. For a fixed wait you'd still use a debounce.
How does useDeferredValue differ from useTransition?
- They are identical
- useTransition only works on the server
- A transition wraps the code that triggers the update (you own the setState); useDeferredValue wraps a value you already have
- useDeferredValue requires Suspense
Answer: A transition wraps the code that triggers the update (you own the setState); useDeferredValue wraps a value you already have. Use a transition when you own the setState. Use a deferred value when you only have a value flowing in — often a prop you can't control.
What's the bug if you pass the live value (not the deferred one) to the heavy child?
- Nothing changes
- Nothing is deferred — the expensive child still updates on every keystroke
- The input stops working
- React throws an error
Answer: Nothing is deferred — the expensive child still updates on every keystroke. Deferring requires feeding the deferred value to the expensive component; passing the live value defeats the entire optimization.
How would you dim stale results in JSX?
- <div hidden={isStale}>
- <div disabled>
- <div className="loading">
- <div style={{ opacity: isStale ? 0.5 : 1 }}>
Answer: <div style={{ opacity: isStale ? 0.5 : 1 }}>. A common pattern sets opacity to 0.5 while value !== deferred, visually signaling that fresher results are on the way.
When is useDeferredValue a better fit than useTransition?
- When you want a fixed delay
- When the slow input is a value (often a prop) you can't wrap the setState for
- When you have no expensive child
- When rendering on the server
Answer: When the slow input is a value (often a prop) you can't wrap the setState for. If you only have a value flowing in and can't control where its setState happens, deferring that value is the right tool.
Besides React.memo, what helps avoid recomputing an expensive filter each render?
- useCallback on the child
- useRef for the result
- useMemo keyed on the deferred value
- Nothing is needed
Answer: useMemo keyed on the deferred value. Wrapping the expensive computation in useMemo keyed on the deferred value avoids recomputing it on unrelated renders.