Skip to content

Commit 5edc1b1

Browse files
committed
Add less history spammy but scuffed search
I rewrote this five times today, all with similar issues. Either you write too much to history, or you overwrite history too much. I'm pretty sure in the current implementation, we don't even need /search as a page
1 parent 7031525 commit 5edc1b1

File tree

1 file changed

+37
-31
lines changed

1 file changed

+37
-31
lines changed

src/components/SearchInput.tsx

Lines changed: 37 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1,58 +1,64 @@
11
import { SearchIcon } from "./Icons";
22
import { useState, useCallback } from "react";
3-
import { useSearchParams, useNavigate } from "react-router-dom";
3+
import { useSearchParams, useNavigate, useLocation } from "react-router-dom";
44

55
const SearchInput = () => {
66
const navigate = useNavigate();
7+
const location = useLocation();
78
const [searchParams, setSearchParams] = useSearchParams();
89
const [searchValue, setSearchValue] = useState(searchParams.get("q") || "");
910

10-
const debouncedSearch = useCallback(
11-
debounce((query: string) => {
12-
if (query) {
13-
setSearchParams({ q: query });
14-
navigate(`/search?q=${encodeURIComponent(query.trim().toLowerCase())}`);
15-
} else {
11+
const navigateToSearch = useCallback(
12+
(query: string, isCompletedSearch = false) => {
13+
const trimmedQuery = query.trim().toLowerCase();
14+
15+
if (!trimmedQuery) {
16+
// Remove search params and navigate to home if query is empty
1617
setSearchParams({});
17-
navigate("/");
18+
navigate("/", { replace: true });
19+
return;
1820
}
19-
}, 200),
20-
[setSearchParams, navigate]
21-
);
2221

23-
const handleSearch = (e: React.ChangeEvent<HTMLInputElement>) => {
24-
const value = e.target.value;
25-
setSearchValue(value);
26-
debouncedSearch(value);
27-
};
22+
// Set the search params with the query
23+
// Use replace: true for keypresses (when isCompletedSearch is false)
24+
setSearchParams({ q: trimmedQuery }, { replace: !isCompletedSearch });
25+
26+
// Only navigate if we're not already on the search page
27+
if (location.pathname !== "/search") {
28+
navigate("/search", {
29+
replace: isCompletedSearch || location.pathname === "/search",
30+
});
31+
}
32+
},
33+
[navigate, location.pathname, setSearchParams]
34+
);
2835

2936
return (
30-
<div className="search-field">
37+
<form
38+
onSubmit={(e) => {
39+
e.preventDefault();
40+
navigateToSearch(searchValue, true);
41+
}}
42+
className="search-field"
43+
>
3144
<label htmlFor="search">
3245
<SearchIcon />
3346
</label>
3447
<input
3548
type="search"
3649
id="search"
3750
value={searchValue}
38-
onChange={handleSearch}
51+
onChange={(e) => {
52+
const newValue = e.target.value;
53+
setSearchValue(newValue);
54+
navigateToSearch(newValue, false);
55+
}}
56+
onBlur={() => navigateToSearch(searchValue, true)}
3957
placeholder="Search here..."
4058
autoComplete="off"
4159
/>
42-
</div>
60+
</form>
4361
);
4462
};
4563

46-
// Debounce utility function
47-
function debounce<T extends (...args: any[]) => any>(
48-
func: T,
49-
wait: number
50-
): (...args: Parameters<T>) => void {
51-
let timeout: ReturnType<typeof setTimeout>;
52-
return (...args: Parameters<T>) => {
53-
clearTimeout(timeout);
54-
timeout = setTimeout(() => func(...args), wait);
55-
};
56-
}
57-
5864
export default SearchInput;

0 commit comments

Comments
 (0)