Improve search effect

This commit is contained in:
Nicolas Mowen 2026-03-24 11:22:56 -06:00
parent a563b9b186
commit 0a7c973518

View File

@ -1,4 +1,11 @@
import { useCallback, useContext, useEffect, useMemo, useRef } from "react"; import {
useCallback,
useContext,
useEffect,
useMemo,
useRef,
useState,
} from "react";
import { useLocation, useNavigate, useSearchParams } from "react-router-dom"; import { useLocation, useNavigate, useSearchParams } from "react-router-dom";
import { usePersistence } from "./use-persistence"; import { usePersistence } from "./use-persistence";
import { useUserPersistence } from "./use-user-persistence"; import { useUserPersistence } from "./use-user-persistence";
@ -200,36 +207,51 @@ export function useSearchEffect(
const location = useLocation(); const location = useLocation();
const navigate = useNavigate(); const navigate = useNavigate();
const [searchParams] = useSearchParams(); const [searchParams] = useSearchParams();
const [pendingRemoval, setPendingRemoval] = useState(false);
const processedRef = useRef<string | null>(null);
const param = useMemo(() => { const currentParam = searchParams.get(key);
const param = searchParams.get(key);
if (!param) {
return undefined;
}
return [key, decodeURIComponent(param)];
}, [searchParams, key]);
// Process the param via callback (once per unique param value)
useEffect(() => { useEffect(() => {
if (!param) { if (currentParam == null || currentParam === processedRef.current) {
return; return;
} }
const remove = callback(param[1]); const decoded = decodeURIComponent(currentParam);
const shouldRemove = callback(decoded);
if (remove) { if (shouldRemove) {
navigate(location.pathname + location.hash, { processedRef.current = currentParam;
state: location.state, setPendingRemoval(true);
replace: true,
});
} }
}, [currentParam, callback, key]);
// Remove the search param in a separate render cycle so that any state
// changes from the callback (e.g., overlay state navigations) are already
// reflected in location.state before we navigate to strip the param.
useEffect(() => {
if (!pendingRemoval) {
return;
}
setPendingRemoval(false);
navigate(location.pathname + location.hash, {
state: location.state,
replace: true,
});
}, [ }, [
param, pendingRemoval,
location.state, navigate,
location.pathname, location.pathname,
location.hash, location.hash,
callback, location.state,
navigate,
]); ]);
// Reset tracking when param is removed from the URL
useEffect(() => {
if (currentParam == null) {
processedRef.current = null;
}
}, [currentParam]);
} }