UNPKG

nuqs

Version:

Type-safe search params state manager for React - Like useState, but stored in the URL query string

93 lines (90 loc) 2.94 kB
import { patchHistory, historyUpdateMarker } from './chunk-TCMXVJZC.js'; import { createAdapterProvider, renderQueryString } from './chunk-5WWTJYGR.js'; import mitt from 'mitt'; import { useCallback, startTransition, useState, useEffect } from 'react'; function createReactRouterBasedAdapter({ adapter, useNavigate, useSearchParams }) { const emitter = mitt(); function useNuqsReactRouterBasedAdapter() { const navigate = useNavigate(); const searchParams = useOptimisticSearchParams(); const updateUrl = useCallback( (search, options) => { startTransition(() => { emitter.emit("update", search); }); const url = new URL(location.href); url.search = renderQueryString(search); const updateMethod = options.history === "push" ? history.pushState : history.replaceState; updateMethod.call( history, history.state, // Maintain the history state historyUpdateMarker, url ); if (options.shallow === false) { navigate( { // Somehow passing the full URL object here strips the search params // when accessing the request.url in loaders. hash: url.hash, search: url.search }, { replace: true, preventScrollReset: true, state: history.state?.usr } ); } if (options.scroll) { window.scrollTo(0, 0); } }, [navigate] ); return { searchParams, updateUrl }; } function useOptimisticSearchParams() { const [serverSearchParams] = useSearchParams( // Note: this will only be taken into account the first time the hook is called, // and cached for subsequent calls, causing problems when mounting components // after shallow updates have occurred. typeof location === "undefined" ? new URLSearchParams() : new URLSearchParams(location.search) ); const [searchParams, setSearchParams] = useState(() => { if (typeof location === "undefined") { return serverSearchParams; } return new URLSearchParams(location.search); }); useEffect(() => { function onPopState() { setSearchParams(new URLSearchParams(location.search)); } function onEmitterUpdate(search) { setSearchParams(search); } emitter.on("update", onEmitterUpdate); window.addEventListener("popstate", onPopState); return () => { emitter.off("update", onEmitterUpdate); window.removeEventListener("popstate", onPopState); }; }, []); return searchParams; } patchHistory(emitter, adapter); return { NuqsAdapter: createAdapterProvider(useNuqsReactRouterBasedAdapter), useOptimisticSearchParams }; } export { createReactRouterBasedAdapter };