UNPKG

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