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
JavaScript
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