import { useSyncExternalStore } from "react"; const subscribe = (callback: (searchParams: string) => void) => { const listener = () => { callback(window.location.search); }; window.addEventListener("popstate", listener); return () => { window.removeEventListener("popstate", listener); }; }; const getSnapshot = () => { return window.location.search; }; const getServerSnapshot = () => { return window.location.search; }; const setSearchParams = (searchParams: Record) => { const url = new URL(window.location.href); Object.entries(searchParams).forEach(([key, value]) => { if (value === undefined || value === null || value === "") { url.searchParams.delete(key); } else { url.searchParams.set(key, value); } }); window.history.pushState({}, "", url); window.dispatchEvent(new PopStateEvent("popstate")); }; export const useSearchParams = () => { // using useSyncExternalStore to get the search params // when the url changes, emit the new value and convert it to an object // return an additional setter to update the search params with an object that is converted to a string and merged with the existing search params const searchParams = useSyncExternalStore( subscribe, getSnapshot, getServerSnapshot ); return { searchParams, setSearchParams, }; };