useId, useTransition & useDeferredValue

0/2 in this phase0/36 across the roadmap

📖 Concept

React 18 introduced several hooks to handle concurrency and accessibility.

1. useId: Generates unique IDs that are stable across the server and client. Essential for accessibility (linking labels to inputs) in SSR/Next.js apps.

2. useTransition: Allows you to mark state updates as "non-urgent". This keeps the UI responsive while a heavy update is happening in the background. It provides a isPending flag to show a loading state.

3. useDeferredValue: Similar to useTransition, but used when you receive a value from props and want to "defer" re-rendering the heavy parts of the UI that depend on that value.

💻 Code Example

codeTap to expand ⛶
1import { useState, useTransition, useDeferredValue, useId } from 'react';
2
3function SearchResults({ query }) {
4 // 1. Defer the heavy list rendering
5 const deferredQuery = useDeferredValue(query);
6
7 // Imagine this is a heavy calculation based on deferredQuery
8 const items = Array.from({ length: 5000 }, (_, i) => `Result ${i} for ${deferredQuery}`);
9
10 return (
11 <ul className="opacity-50 transition-opacity duration-500" style={{ opacity: query !== deferredQuery ? 0.5 : 1 }}>
12 {items.map(item => <li key={item}>{item}</li>)}
13 </ul>
14 );
15}
16
17function App() {
18 const [query, setQuery] = useState('');
19 const [isPending, startTransition] = useTransition();
20 const id = useId(); // 2. Stable ID for accessibility
21
22 const handleChange = (e) => {
23 // 3. Keep the input feeling snappy!
24 const value = e.target.value;
25 setQuery(value);
26 };
27
28 return (
29 <div className="p-10">
30 <label htmlFor={id}>Search:</label>
31 <input
32 id={id}
33 value={query}
34 onChange={handleChange}
35 className="border p-2 ml-2"
36 />
37
38 {isPending && <p>Loading new results...</p>}
39
40 <SearchResults query={query} />
41 </div>
42 );
43}

🏋️ Practice Exercise

  1. Implement useId in a reusable 'Input' component to link the label and input correctly.
  2. Build a large list filter and use useTransition to show a 'pending' state while the list updates.
  3. Compare useDeferredValue with a traditional debounce function.
  4. Research why useId is better than Math.random() for generating IDs in React.

⚠️ Common Mistakes

  • Using useTransition for small, fast updates where it just adds unnecessary complexity.

  • Thinking useDeferredValue works like a debounce (it's actually more intelligent; it only defers if the CPU is busy).

  • Using useId as a 'key' in a list (keys should come from your data, not be generated by hooks).

💼 Interview Questions

🎤 Mock Interview

Practice a live interview for useId, useTransition & useDeferredValue