Debounced product search

React · React · advanced · greenfield

Adds the ProductSearch component: a debounced effect issues the request 300 ms after the last keystroke, an AbortController cancels the in-flight request whenever the query changes or the component unmounts, and an aborted-signal guard after the await keeps any cancelled or already-resolved stale response from touching state. Loading, error and empty states are all rendered.

Requirements

Files touched

--- src/components/ProductSearch.jsx
+import { useEffect, useState } from 'react';
+import { searchProducts } from '../api/search';
+
+const DEBOUNCE_MS = 300;
+
+function ProductSearch() {
+  const [query, setQuery] = useState('');
+  const [results, setResults] = useState([]);
+  const [status, setStatus] = useState('idle');
+
+  useEffect(() => {
+    const trimmed = query.trim();
+    if (trimmed === '') {
+      setResults([]);
+      setStatus('idle');
+      return undefined;
+    }
+    const controller = new AbortController();
+    const timer = setTimeout(async () => {
+      setStatus('loading');
+      try {
+        const found = await searchProducts(trimmed, { signal: controller.signal });
+        if (controller.signal.aborted) return;
+        setResults(found);
+        setStatus('done');
+      } catch {
+        if (controller.signal.aborted) return;
+        setStatus('error');
+      }

Review this PR

React practice