UNPKG

stateful-params

Version:

A lightweight and intuitive React hook for managing URL query parameters with ease. Stateful-params enables seamless CRUD operations on URL query parameters while keeping your UI in sync with the URL state. Perfect for building dynamic, stateful, and shar

120 lines (100 loc) 3.72 kB
import { useState, useEffect } from "react" /** * Hook for managing URL query parameters * @template TParams - The shape of the query parameters. * @param {object} [options] - Configuration options. * @param {boolean} [options.deleteFalseValues=false] - Whether to delete the parameter if the parameter value is a false value. * @param {'replace' | 'push'} [options.method='push'] - Method to use for history updates. * @returns {object} - An object containing methods to set, append, get, delete query parameters and searchParams. */ export const useStatefulParams = <TParams extends Record<string, any>>( options: { method?: "replace" | "push" deleteFalseValues?: boolean } = {} ) => { const { method = "push", deleteFalseValues = true } = options const [searchParams, setSearchParams] = useState<URLSearchParams>(() => { return new URLSearchParams(window.location.search) }) useEffect(() => { const handlePopState = () => { const newParams = new URLSearchParams(window.location.search) setSearchParams(newParams) } window.addEventListener("popstate", handlePopState) return () => window.removeEventListener("popstate", handlePopState) }, []) const updateUrl = (newParams: URLSearchParams) => { const newParamsString = newParams.toString() const currentParamsString = searchParams.toString() if (newParamsString !== currentParamsString) { const newUrl = new URL(window.location.href) newUrl.search = newParamsString if (method === "replace") { window.history.replaceState(null, "", newUrl) } else { window.history.pushState(null, "", newUrl) } setSearchParams(newParams) } } const set = (params: Partial<TParams>) => { const newSearchParams = new URLSearchParams(searchParams.toString()) for (const [key, value] of Object.entries(params)) { if ( value === null || value === undefined || (deleteFalseValues && !value) ) { newSearchParams.delete(key) } else if (Array.isArray(value)) { newSearchParams.delete(key) value.forEach(val => newSearchParams.append(key, String(val))) } else { newSearchParams.set(key, String(value)) } } updateUrl(newSearchParams) return Object.fromEntries(newSearchParams.entries()) } const append = (params: Partial<TParams>) => { const newSearchParams = new URLSearchParams(searchParams.toString()) for (const [key, value] of Object.entries(params)) { if (Array.isArray(value)) { value.forEach(val => newSearchParams.append(key, String(val))) } else { newSearchParams.append(key, String(value)) } } updateUrl(newSearchParams) return Object.fromEntries(newSearchParams.entries()) } const deleteParam = (keys: keyof TParams | (keyof TParams)[]) => { const newSearchParams = new URLSearchParams(searchParams.toString()) if (Array.isArray(keys)) { keys.forEach(key => newSearchParams.delete(key as string)) } else { newSearchParams.delete(keys as string) } updateUrl(newSearchParams) return Object.fromEntries(newSearchParams.entries()) } const clear = () => { const newSearchParams = new URLSearchParams() updateUrl(newSearchParams) return Object.fromEntries(newSearchParams.entries()) } const get = <K extends keyof TParams>(key: K): TParams[K] | null => { return searchParams.get(key as string) as TParams[K] | null } const searchParamsObj = Object.fromEntries(searchParams.entries()) as TParams return { set, append, deleteParam, clear, get, searchParams: searchParamsObj } }