Real World Example

Real World: Contacts search in a CRM

Typing in the search box must stay smooth while a list of 20,000 contacts filters. useDeferredValue lets the list update a moment later; useId links each label to its input in a reusable form field.

function ContactSearch({ contacts }) {
  const [query, setQuery] = useState('');
  const deferredQuery = useDeferredValue(query);
  const results = useMemo(
    () => contacts.filter((c) => c.name.toLowerCase().includes(deferredQuery.toLowerCase())),
    [contacts, deferredQuery],
  );
  return (
    <>
      <input value={query} onChange={(e) => setQuery(e.target.value)} />
      <ContactList items={results} />
    </>
  );
}