useTransition is a React 18 hook for marking state updates as non-urgent. Non-urgent updates can be paused or interrupted to keep the UI responsive.
- Search filters with large datasets
- Tab or route changes with expensive rendering
- Rendering charts/graphs while keeping input smooth
- Any UI where urgent updates (typing, clicking) should not be blocked
// search.tsx
import { useState, useTransition, type ChangeEvent, type FC } from "react";
import { faker } from '@faker-js/faker';
import List from "./List";
const Search: FC = () => {
const list = Array.from({length : 20}, (_ , i) => ({ id : i , name : faker.person.fullName() , email : faker.internet.email() }));
console.log(JSON.stringify(list,null, 2));
const [input, setInput] = useState<string>('');
const [query, setQuery] = useState<string>('');
const [isPending, startTransition]:[boolean, (callback : () => void) => void] = useTransition();
const setValInput = (e : ChangeEvent<HTMLInputElement>) :void => {
setInput(e.target.value);
startTransition(() => {
setQuery(input);
});
}
return (
<>
<input type="text" onChange={(e) => setValInput(e)}/>
{isPending && <p>List is Loading...</p>}
<List query={query} list={list}/>
</>
)
}
export default Search;
// List.tsx
import type { FC } from "react";
interface ListProps {
query: string;
list: Person[];
}
interface Person {
id: number;
name: string;
email: string;
}
const List : FC<ListProps> = ({query, list}: ListProps) => {
const regex = new RegExp(query, "i");
const filtered = list.filter(el => regex.test(el.name));
return (
<ul>
{filtered.map((person: Person) => (
<li key={person.id}>
{person.name} : {person.email}
</li>
))}
</ul>
)
}
export default List;
