01Inline useEffect + setTimeout
-Debounce logic lives directly inside the component that owns the input.
-export function TaskSearch() { - const [draft, setDraft] = useState(''); - const [query, setQuery] = useState(''); - - useEffect(() => { - const id = setTimeout(() => setQuery(draft), 300); - return () => clearTimeout(id); - }, [draft]); - - const { data } = useTasks({ search: query }); - - return ( - <input - value={draft} - onChange={(e) => setDraft(e.target.value)} - placeholder="Filter tasks…" - /> - ); -}
Blocking
-onMutatedoesn't callqc.cancelQueries(key)first. If a background refetch lands between the optimistic write and the server response, it will clobber the optimistic state and the UI will flicker back to the old value.NitRollback restores the list but never surfaces the error. Consider wiring the existing
-pushToasthere so users know the toggle didn't stick.