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.45 kB
JavaScript
import u from"react";import{TIMEOUT as T}from"../constants/constants.mjs";import{useIsomorphicLayoutEffect as L}from"../useIsomorphicLayoutEffect.mjs";import{useSharedState as P}from"../useSharedState/useSharedState.mjs";import{useUrlEncode as b}from"../useUrlEncode/useUrlEncode.mjs";import{getSearch as l,popstateEv as v,filterUnknownParamsClient as I,getOtherParams as O}from"../utils.mjs";let i;let o;function x(t,r,g,S){const{parse:p,stringify:d}=b(t);const{state:$,getState:s,setState:n}=P(t,()=>g?.({parse:p})||t);const a=u.useRef();if(a.current===void 0)a.current=l();L(()=>{const e=()=>{n(p(I(t,l())))};window.addEventListener(v,e);if(a.current!==l())e();return()=>{window.removeEventListener(v,e)}},[]);const c=u.useCallback((e,U)=>{const m=typeof e==="function"?e(s(),t):{...s(),...e};const f=d(m,O(t,window.location.search));const h=B(window.location.pathname,S);const w=`${h}${f.length?"?":""}${f}${window.location.hash}`;const k=`${h}${window.location.search}${window.location.hash}`;if(w===k)return;n(m);const{replace:y,...C}=U||{};clearTimeout(i);i=void 0;o={router:r,method:y?"replace":"push",url:w,opts:C};i=setTimeout(()=>{if(o){o.router[o.method](o.url,o.opts);o=void 0}i=void 0},T)},[r,d,s]);const E=u.useCallback(e=>{n(t);c(t,e)},[c,n]);return{updateState:n,updateUrl:c,state:$,reset:E,getState:s,pendingUrlUpdate:()=>i!==void 0}}function B(t,r){if(!r||r==="/"){return t}return t.slice(r.length)}export{x as useUrlStateBase};