UNPKG

qs-state-hook

Version:
111 lines (104 loc) 3.76 kB
'use strict'; var react = require('react'); var qs = require('qs'); var debounce = require('lodash.debounce'); function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; } var qs__default = /*#__PURE__*/_interopDefaultLegacy(qs); var debounce__default = /*#__PURE__*/_interopDefaultLegacy(debounce); const theLocation = typeof window !== "undefined" ? window.location : { search: "" }; const push = ({ search }) => { const url = new URL(theLocation.toString?.() || ""); url.search = search; history.pushState("", "", url.toString()); }; var history$1 = { location: theLocation, push }; function isEqualObj(a, b) { if (a === b) return true; return JSON.stringify(a) === JSON.stringify(b); } const COMMIT_DELAY = 100; let commitQueue = {}; const identityFn = (v) => v; function useQsStateCreator(options = {}) { const { commit: commitToLocation = history$1.push } = options; const location = react.useRef({ search: "" }); location.current = options.location || history$1.location; const commit = react.useMemo(() => debounce__default["default"](() => { const parsedQS = qs__default["default"].parse(location.current?.search || "", { ignoreQueryPrefix: true }); const qsObject = { ...parsedQS, ...commitQueue }; commitToLocation({ search: qs__default["default"].stringify(qsObject, { skipNulls: true }) }); commitQueue = {}; }, COMMIT_DELAY), [commitToLocation]); const storeInURL = react.useCallback((k, v) => { commitQueue = { ...commitQueue, [k]: v }; commit(); }, [commit]); return react.useMemo(() => qsStateFactory({ storeInURL, location: location.current }), [storeInURL]); } function qsStateFactory({ storeInURL, location }) { function useQsState(def) { const mounted = react.useRef(false); const { hydrator = identityFn, dehydrator = identityFn } = def; const locSearch = location.search; const validator = react.useCallback((v) => { const userValidator = def.validator; if (Array.isArray(userValidator)) { return userValidator.indexOf(v) !== -1; } else if (typeof userValidator === "function") { return userValidator(v); } else { return !!v; } }, [def.validator]); const getValueFromURL = (searchString) => { const parsedQS = qs__default["default"].parse(searchString, { ignoreQueryPrefix: true }); const value = hydrator(parsedQS[def.key]); return validator(value) ? value : def.default; }; const [valueState, setValueState] = react.useState(getValueFromURL(locSearch)); const stateRef = react.useRef(); stateRef.current = valueState; const setValue = react.useCallback((value) => { const v = validator(value) ? value : def.default; const dehydratedVal = dehydrator(v); setValueState(v); const dehydratedDefaultVal = dehydrator(def.default); storeInURL(def.key, dehydratedVal !== dehydratedDefaultVal ? dehydratedVal : null); }, [validator, def.default, def.key, dehydrator, storeInURL]); react.useEffect(() => { if (!mounted.current) { mounted.current = true; return; } const v = getValueFromURL(locSearch); const hasPendingCommits = Object.keys(commitQueue).length; if (!hasPendingCommits && !isEqualObj(v, stateRef.current)) { setValueState(v); } }, [locSearch, def]); return [valueState, setValue]; } useQsState.memo = function useQsStateMemoized(def, deps = []) { return useQsState(react.useMemo(() => def, [...deps, storeInURL])); }; return useQsState; } module.exports = useQsStateCreator; //# sourceMappingURL=index.js.map