#搜索框
一个搜索框对应一个 URL search param。输入内容会写入 search,清空时会删除对应 key。
Search products
The input value is stored in the example_keyword search param.
location.search(empty)
import { useSearchValue } from '@guanriyue/decurl';
import { field } from '@guanriyue/decurl/codec';
import { Search, X } from 'lucide-react';
import { useLocation } from 'react-router';
import { Badge } from '@/components/ui/badge';
import { Button } from '@/components/ui/button';
import { Input } from '@/components/ui/input';
import { Label } from '@/components/ui/label';
const searchField = field({
name: 'example_keyword',
decode: (value: string) => {
const nextValue = value.trim();
return nextValue.length > 0 ? nextValue : undefined;
},
defaultValue: '',
});
const SearchBox = () => {
const location = useLocation();
const [keyword, setKeyword] = useSearchValue(searchField);
return (
<section className="mx-auto max-w-xl space-y-5 p-4">
<div className="space-y-1.5">
<h2 className="text-base font-semibold">Search products</h2>
<p className="text-sm text-muted-foreground">
The input value is stored in the example_keyword search param.
</p>
</div>
<div className="space-y-2">
<Label htmlFor="example-keyword">Keyword</Label>
<div className="flex gap-2">
<div className="relative min-w-0 flex-1">
<Search className="pointer-events-none absolute top-1/2 left-3 size-4 -translate-y-1/2 text-muted-foreground" />
<Input
id="example-keyword"
className="pl-9"
placeholder="router, docs, search..."
value={keyword}
onChange={(event) => {
setKeyword(event.currentTarget.value);
}}
/>
</div>
<Button
aria-label="Clear keyword"
disabled={keyword.length === 0}
type="button"
variant="outline"
onClick={() => {
setKeyword(undefined);
}}
>
<X />
Clear
</Button>
</div>
</div>
<div className="flex flex-wrap items-center gap-2 text-sm">
<span className="text-muted-foreground">location.search</span>
<Badge variant="outline" className="font-mono">
{location.search || '(empty)'}
</Badge>
</div>
</section>
);
};
export default SearchBox;
涉及 API: