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