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.08 kB
JavaScript
import s from"react";import{useRouter as k,useSearchParams as C}from"next/navigation";import{parseSPObj as p}from"../../parseSPObj.mjs";import{useUrlStateBase as y}from"../../useUrlStateBase/useUrlStateBase.mjs";import{routerHistory as m,filterUnknownParams as f,isSSR as g,filterUnknownParamsClient as j}from"../../utils.mjs";function v(t,r){const a=r?.useHistory;const o=k();const S=s.useMemo(()=>({push:(...e)=>{if(a===void 0?true:!!a){m.push(...e)}else{o.push(...e)}},replace:(...e)=>{if(a===void 0?true:!!a){m.replace(...e)}else{o.replace(...e)}}}),[o]);const{state:h,updateState:l,updateUrl:c,reset:u,getState:P}=y(t,S,({parse:e})=>{return g?p(f(t,r?.searchParams),t):e(j(t,r?.searchParams))});const n=s.useMemo(()=>({...w,scroll:r?.scroll,replace:r?.replace}),[]);const U=s.useCallback((e,d)=>c(e,{...n,...d}),[c]);const i=C();s.useLayoutEffect(()=>{l(f(t,p(Object.fromEntries([...i.entries()]),t)))},[i]);const b=s.useCallback(e=>{u({...n,...e})},[u]);return{setState:l,setUrl:U,urlState:h,reset:b,getState:P}}const w={replace:true,scroll:false};export{v as useUrlState};