nuqs
Version:
Type-safe search params state manager for React - Like useState, but stored in the URL query string
75 lines (72 loc) • 3.18 kB
JavaScript
'use client';
import { createEmitter } from "../debounce-CmqzOOem.js";
import { createAdapterProvider, debug, renderQueryString } from "../context-BWo_DoaC.js";
import { applyChange, filterSearchParams } from "../key-isolation-CKEBJ11E.js";
import "../reset-BmRuoRYl.js";
import { historyUpdateMarker, patchHistory } from "../patch-history-VL_JehFX.js";
import { createContext, createElement, useContext, useEffect, useMemo, useState } from "react";
//#region src/adapters/react.ts
const emitter = createEmitter();
function generateUpdateUrlFn(fullPageNavigationOnShallowFalseUpdates) {
return function updateUrl(search, options) {
const url = new URL(location.href);
url.search = renderQueryString(search);
debug("[nuqs react] Updating url: %s", url);
if (fullPageNavigationOnShallowFalseUpdates && options.shallow === false) {
const method = options.history === "push" ? location.assign : location.replace;
method.call(location, url);
} else {
const method = options.history === "push" ? history.pushState : history.replaceState;
method.call(history, history.state, historyUpdateMarker, url);
}
emitter.emit("update", search);
if (options.scroll === true) window.scrollTo({ top: 0 });
};
}
const NuqsReactAdapterContext = createContext({ fullPageNavigationOnShallowFalseUpdates: false });
function useNuqsReactAdapter(watchKeys) {
const { fullPageNavigationOnShallowFalseUpdates } = useContext(NuqsReactAdapterContext);
const [searchParams, setSearchParams] = useState(() => {
if (typeof location === "undefined") return new URLSearchParams();
return filterSearchParams(new URLSearchParams(location.search), watchKeys, false);
});
useEffect(() => {
const onPopState = () => {
setSearchParams(applyChange(new URLSearchParams(location.search), watchKeys, false));
};
const 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("&")]);
const updateUrl = useMemo(() => generateUpdateUrlFn(fullPageNavigationOnShallowFalseUpdates), [fullPageNavigationOnShallowFalseUpdates]);
return {
searchParams,
updateUrl
};
}
const NuqsReactAdapter = createAdapterProvider(useNuqsReactAdapter);
function NuqsAdapter({ children, fullPageNavigationOnShallowFalseUpdates = false,...adapterProps }) {
return createElement(NuqsReactAdapterContext.Provider, { value: { fullPageNavigationOnShallowFalseUpdates } }, createElement(NuqsReactAdapter, {
...adapterProps,
children
}));
}
/**
* Opt-in to syncing 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.
*/
function enableHistorySync() {
patchHistory(emitter, "react");
}
//#endregion
export { NuqsAdapter, enableHistorySync };
//# sourceMappingURL=react.js.map