Concurrent features
- React course
- Expert
- Lesson 28/32
- 5 min
Make a heavy filter low priority with useTransition.
Concurrent features
In the last step you add concurrent search to the project. The SearchPanel component does the search in the background with useTransition; the input stays smooth.
The starting code includes the previous three solutions. This lesson only adds SearchPanel. So the design system, theme, server page and concurrent search merge in one project.
With isPending a loading indicator is shown during the wait.
Pending with isPending
While isPending is true you show a waiting indicator to the user. This signals that the search is running in the background. The indicator should be short and meaningful; the user must know what they are waiting for. When the search finishes the indicator disappears and the result list appears. This keeps the app looking responsive and the user experience uninterrupted.
Practice Write the SearchPanel component
Write SearchPanel. Import useState and useTransition. Keep query with useState(''), get isPending and startTransition from useTransition. Compute items.filter(i => i.name.includes(query)) as filtered. Show <input value={query} onChange={e => startTransition(() => setQuery(e.target.value))} /> and isPending ? <p>Searching</p> : <ul>{filtered.map(...)}</ul>. Export it.
Starter code
// Button.jsx
function Button({ variant, children }) {
const className = variant === 'primary' ? 'btn-primary' : 'btn-secondary';
return <button className={className}>{children}</button>;
}
export default Button;
// ThemeProvider.jsx
import { createContext, useState } from 'react';
const ThemeContext = createContext();
function ThemeProvider({ children }) {
const [theme, setTheme] = useState('light');
return (
<ThemeContext.Provider value={{ theme, setTheme }}>
{children}
</ThemeContext.Provider>
);
}
export default ThemeProvider;
// ProductPage.jsx
async function ProductPage() {
const res = await fetch('/api/products');
const products = await res.json();
return (
<main>
<h1>Ürünler</h1>
<ul>{products.map(p => <li key={p.id}>{p.name}</li>)}</ul>
</main>
);
}
export default ProductPage;
// SearchPanel.jsx
// Write the SearchPanel component hereSample solution
import { useState, useTransition } from 'react';
function SearchPanel({ items }) {
const [query, setQuery] = useState('');
const [isPending, startTransition] = useTransition();
const filtered = items.filter(i => i.name.includes(query));
return (
<div>
<input value={query} onChange={e => startTransition(() => setQuery(e.target.value))} />
{isPending ? <p>Searching</p> : <ul>{filtered.map(i => <li key={i.id}>{i.name}</li>)}</ul>}
</div>
);
}
export default SearchPanel;Questions and answers
Review the lesson questions together with their answers. To test yourself, solve the lesson interactively.
1 Which hook does SearchPanel use?
- useTransition Correct answer
- useRef
- useReducer
- useEffect
Explanation: useTransition runs the search in the background.
2 Fill in the blank: start a transition
const [isPending, startTransition] = use____();
const [isPending, startTransition] = useTransition();
Explanation: useTransition starts a transition.
3 Match concurrent concepts
| Term | Meaning |
|---|---|
useTransition |
Deferred update |
isPending |
Pending state |
startTransition |
Wraps the update |
input |
Stays smooth |