SPB Git forge
38commits 1branches 0releases
338.7 MBsize
maindefault branch
4 h agolast push
HTML 53.9% TypeScript 44.5% JavaScript 0.6% SQL 0.5%
1.3 KB · 34 lines typescript
Raw Blame History
1"use client";23import { usePathname, useRouter, useSearchParams } from "next/navigation";4import { useCallback, useMemo } from "react";56/** URL search params as state: `set({ key: value | null })` replaces the URL (no scroll, no history entry). */7export function useUrlState(): [Record<string, string>, (patch: Record<string, string | number | boolean | null | undefined>, opts?: { push?: boolean }) => void] {8  const sp = useSearchParams();9  const router = useRouter();10  const pathname = usePathname();11  const params = useMemo(() => {12    const out: Record<string, string> = {};13    sp.forEach((v, k) => {14      out[k] = v;15    });16    return out;17  }, [sp]);18  const set = useCallback(19    (patch: Record<string, string | number | boolean | null | undefined>, opts?: { push?: boolean }) => {20      const next = new URLSearchParams(sp.toString());21      for (const [k, v] of Object.entries(patch)) {22        if (v === null || v === undefined || v === "" || v === false) next.delete(k);23        else next.set(k, v === true ? "1" : String(v));24      }25      const qs = next.toString();26      const url = qs ? `${pathname}?${qs}` : pathname;27      if (opts?.push) router.push(url, { scroll: false });28      else router.replace(url, { scroll: false });29    },30    [sp, router, pathname],31  );32  return [params, set];33}34