state-in-url
Version:
Store state in URL as in object, types and structure are preserved, with TS validation. Same API as React.useState, wthout any hasssle or boilerplate. Next.js@14-15, react-router@6-7, and remix@2.
2 lines (1 loc) • 1.55 kB
JavaScript
;var _=require("react");var k=require("../constants/constants.js");var C=require("../useIsomorphicLayoutEffect.js");var L=require("../useSharedState/useSharedState.js");var T=require("../useUrlEncode/useUrlEncode.js");var r=require("../utils.js");function I(t){return t&&t.__esModule?t:{default:t}}var l=I(_);let s;let o;function P(t,a,S,m){const{parse:d,stringify:f}=T.useUrlEncode(t);const{state:g,getState:u,setState:n}=L.useSharedState(t,()=>S?.({parse:d})||t);const i=l.default.useRef();if(i.current===void 0)i.current=r.getSearch();C.useIsomorphicLayoutEffect(()=>{const e=()=>{n(d(r.filterUnknownParamsClient(t,r.getSearch())))};window.addEventListener(r.popstateEv,e);if(i.current!==r.getSearch())e();return()=>{window.removeEventListener(r.popstateEv,e)}},[]);const c=l.default.useCallback((e,U)=>{const h=typeof e==="function"?e(u(),t):{...u(),...e};const p=f(h,r.getOtherParams(t,window.location.search));const v=b(window.location.pathname,m);const w=`${v}${p.length?"?":""}${p}${window.location.hash}`;const $=`${v}${window.location.search}${window.location.hash}`;if(w===$)return;n(h);const{replace:q,...y}=U||{};clearTimeout(s);s=void 0;o={router:a,method:q?"replace":"push",url:w,opts:y};s=setTimeout(()=>{if(o){o.router[o.method](o.url,o.opts);o=void 0}s=void 0},k.TIMEOUT)},[a,f,u]);const E=l.default.useCallback(e=>{n(t);c(t,e)},[c,n]);return{updateState:n,updateUrl:c,state:g,reset:E,getState:u,pendingUrlUpdate:()=>s!==void 0}}function b(t,a){if(!a||a==="/"){return t}return t.slice(a.length)}exports.useUrlStateBase=P;