cf.completefrontend

Write the codeHard

Write a useDeferredSearch hook that keeps old results, marked stale, while new ones render

Write useDeferredSearch(items, query, search). It returns { results, isStale }, where results is search(items, someQuery). The point is to keep a search box responsive next to a slow results list: the box should update at once, and the results should catch up in a background render that a newer key can interrupt.

So when query changes, the first (urgent) render must not search: it returns the results it already has, the very same array, with isStale: true. Then a background render searches with the new query and returns isStale: false. On the first render it searches with query straight away and isn't stale. A render for any other reason doesn't search again; a new items list or a new search function does. Here's how a component uses it:

const ResultList = memo(function ResultList({ results }) {
  return <ul>{results.map((tea) => <li key={tea.id}>{tea.name}</li>)}</ul>;
});
 
function TeaSearch({ teas }) {
  const [query, setQuery] = useState("");
  const { results, isStale } = useDeferredSearch(teas, query, searchByName);
  return (
    <>
      <input aria-label="Search" value={query} onChange={(e) => setQuery(e.target.value)} />
      <section aria-busy={isStale} style={{ opacity: isStale ? 0.5 : 1 }}>
        <ResultList results={results} />
      </section>
    </>
  );
}
Write this (useDeferredSearch.js)
import { useDeferredValue, useMemo } from "react";
 
export function useDeferredSearch(items, query, search) {
  // Search with a deferred copy of query, and say when the results are behind.
  return { results: search(items, query), isStale: false };
}
The checks your code must pass
  • searches with the query on the first render, not stale
  • a new query first returns the old results, marked stale, then the new ones
  • the stale render returns the very same results array
  • searches once per new query, in the background render only
  • renders for other reasons don't search again
  • a new items list or search function searches again
  • a memo list renders once per key, and the section ends up not busy

Try it in the editor

The answer

Write it yourself first. Then compare it with a reference solution and the checks it passes.

Checking your sign-in…