UNPKG

@baurine/use-url-state

Version:

react useUrlState hook

68 lines (65 loc) 2.19 kB
import { jsx } from 'react/jsx-runtime'; import { createContext, useState, useMemo, useContext } from 'react'; const UrlStateContext = createContext(null); const useUrlStateContext = () => { const context = useContext(UrlStateContext); if (!context) { throw new Error('useUrlStateContext must be used within a UrlStateProvider'); } return context; }; function defCtxVal() { return { urlQuery: new URL(window.location.href).search, setUrlQuery(p) { const url = new URL(window.location.href); window.history.replaceState({}, '', `${url.pathname}?${p}`); } }; } function UrlStateProvider(props) { const val = props.value || defCtxVal(); const [urlQuery, _setUrlQuery] = useState(val.urlQuery); // UrlStateProvider is designed to each page has its own provider instance, // won't share between pages // so we don't need to sync urlQuery from props // ------------------- // sync urlQuery from props changes // useEffect(() => { // _setUrlQuery(val.urlQuery) // }, [val.urlQuery]) const ctxValue = useMemo(() => ({ urlQuery, setUrlQuery: (v) => { val.setUrlQuery(v); // trigger re-render _setUrlQuery(v); } }), [urlQuery, val]); return (jsx(UrlStateContext.Provider, { value: ctxValue, children: props.children })); } function useUrlState() { const { urlQuery, setUrlQuery } = useUrlStateContext(); const queryParams = useMemo(() => { const searchParams = new URLSearchParams(urlQuery); const paramsObj = {}; searchParams.forEach((v, k) => { paramsObj[k] = v; }); return paramsObj; }, [urlQuery]); function setQueryParams(s) { const searchParams = new URLSearchParams(urlQuery); Object.keys(s).forEach((k) => { if (s[k]) { searchParams.set(k, s[k]); } else { searchParams.delete(k); } }); setUrlQuery(searchParams.toString()); } return [queryParams, setQueryParams]; } export { UrlStateProvider, useUrlState };