UNPKG

nuqs

Version:

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

86 lines (84 loc) 3.45 kB
import { createEmitter, globalThrottleQueue } from "./debounce-CmqzOOem.js"; import { createAdapterProvider, debug, renderQueryString } from "./context-BWo_DoaC.js"; import { applyChange, filterSearchParams } from "./key-isolation-CKEBJ11E.js"; import { setQueueResetMutex } from "./reset-BmRuoRYl.js"; import { historyUpdateMarker, patchHistory } from "./patch-history-VL_JehFX.js"; import { startTransition, useCallback, useEffect, useRef, useState } from "react"; //#region src/adapters/lib/react-router.ts function createReactRouterBasedAdapter({ adapter, useNavigate, useSearchParams }) { const emitter = createEmitter(); const enableQueueReset = adapter !== "react-router-v6"; function useNuqsReactRouterBasedAdapter(watchKeys) { const resetRef = useRef(false); if (enableQueueReset && resetRef.current) { resetRef.current = false; globalThrottleQueue.reset(); } const navigate = useNavigate(); const searchParams = useOptimisticSearchParams(watchKeys); const updateUrl = useCallback((search, options) => { startTransition(() => { emitter.emit("update", search); }); const url = new URL(location.href); url.search = renderQueryString(search); debug(`[nuqs ${adapter}] Updating url: %s`, url); const updateMethod = options.history === "push" ? history.pushState : history.replaceState; setQueueResetMutex(options.shallow ? 1 : 2); updateMethod.call(history, history.state, historyUpdateMarker, url); if (options.shallow === false) navigate({ hash: url.hash, search: url.search }, { replace: true, preventScrollReset: true, state: history.state?.usr }); if (options.scroll) window.scrollTo(0, 0); resetRef.current = enableQueueReset; }, [navigate]); return { searchParams, updateUrl, autoResetQueueOnUpdate: false }; } function useOptimisticSearchParams(watchKeys = []) { const [serverSearchParams] = useSearchParams(typeof location === "undefined" ? new URLSearchParams() : new URLSearchParams(location.search)); const [searchParams, setSearchParams] = useState(() => { return typeof location === "undefined" ? filterSearchParams(serverSearchParams, watchKeys, true) : filterSearchParams(new URLSearchParams(location.search), watchKeys, false); }); useEffect(() => { function onPopState() { setSearchParams(applyChange(new URLSearchParams(location.search), watchKeys, false)); } function onEmitterUpdate(search) { setSearchParams(applyChange(search, watchKeys, true)); } emitter.on("update", onEmitterUpdate); window.addEventListener("popstate", onPopState); return () => { emitter.off("update", onEmitterUpdate); window.removeEventListener("popstate", onPopState); }; }, [watchKeys.join("&")]); return searchParams; } /** * Sync shallow updates of the URL with the useOptimisticSearchParams hook. * * By default, the useOptimisticSearchParams hook will only react to internal nuqs updates. * If third party code updates the History API directly, use this function to * enable useOptimisticSearchParams to react to those changes. * * Note: this is actually required in React Router frameworks to follow Link navigations. */ patchHistory(emitter, adapter); return { NuqsAdapter: createAdapterProvider(useNuqsReactRouterBasedAdapter), useOptimisticSearchParams }; } //#endregion export { createReactRouterBasedAdapter }; //# sourceMappingURL=react-router-Dm6lbMS2.js.map