Prompt
Build a product search screen. Requirements:
- Render products from a mock list (name, price, category)
- Search by name (case-insensitive, debounced 300ms)
- Sort by: name A-Z, name Z-A, price low-high, price high-low
- Mark items with price <= 100 as "on sale"
Solution
The point of this screen is the debounce done the React way: an effect keyed on query that schedules a setTimeout and returns clearTimeout as cleanup. Every keystroke re-runs the effect, cancelling the previous timer — the cancellation is the debounce. No lodash, no ref juggling.
The two-state split matters: query drives the controlled TextInput so typing echoes instantly; debounced drives the filter so the expensive work runs 300ms after the user pauses. Debounce the consumer of the value, never the controlled value itself — a debounced value prop makes the keyboard feel broken.
Filter-then-sort is deliberate ordering: .filter() returns a fresh array, so the subsequent .sort() — which sorts in place — mutates only the copy, never PRODUCTS. Sort straight on the source array and the "original" order is gone for every later render. The comparator is a flat if-chain over the four sort keys with localeCompare for strings and subtraction for numbers; a lookup table of comparators is the refactor when the options grow.
Red flag: storing the filtered/sorted result in state via another effect. Query, sort key, and source list fully determine the output — derive it in render, useMemo it if the catalog gets big.
Say it: "I debounce with an effect whose cleanup cancels the previous timer — the raw query stays controlled for instant echo, and the filtered list is derived, never stored."