JSPM

@baurine/use-url-state

0.1.0
    • ESM via JSPM
    • ES Module Entrypoint
    • Export Map
    • Keywords
    • License
    • Repository URL
    • TypeScript Types
    • README
    • Created
    • Published
    • 0
    • Score
      100M100P100Q33593F
    • License MIT

    react useUrlState hook

    Package Exports

    • @baurine/use-url-state
    • @baurine/use-url-state/dist/index.js

    This package does not declare an exports field, so the exports above have been automatically detected and optimized by JSPM instead. If any package subpath is missing, it is recommended to post an issue to the original package (@baurine/use-url-state) to support the "exports" field. If that is not possible, create a JSPM override to customize the exports field for this package.

    Readme

    @baurine/use-url-state

    A very lightweight react hook to manage state in the url.

    This hook doesn't depend on any router libs (not like @ahooks/use-state-url), it can be used with none router or any router libs.

    Installation

    npm install @baurine/use-url-state
    # or
    pnpm add @baurine/use-url-state
    # or
    yarn add @baurine/use-url-state

    Usage

    Step 1

    Use UrlStateProvider in the top level, wrap <App /> component.

    import { UrlStateProvider } from '@baurine/use-url-state'
    import React from 'react'
    import ReactDOM from 'react-dom/client'
    
    import App from './App.tsx'
    
    ReactDOM.createRoot(document.getElementById('root')!).render(
      <React.StrictMode>
        <UrlStateProvider>
          <App />
        </UrlStateProvider>
      </React.StrictMode>
    )

    The UrlStateProvider has default value:

    function defCtxVal(): UrlStateCtxValue {
      return {
        urlQuery: new URL(window.location.href).search,
        setUrlQuery(p) {
          const url = new URL(window.location.href)
          window.history.replaceState({}, '', `${url.pathname}?${p}`)
        }
      }
    }

    The default value is only suitable for working with none router lib. If your app works with a router lib, you need to write a adapter.

    Adapter for react-router v5:

    import { useLocation, useHistory } from 'react-router-dom'
    
    function ReactRouter5UrlStateProvider(props: { children: React.ReactNode }) {
      const loc = useLocation()
      const history = useHistory()
    
      return (
        <UrlStateProvider
          value={{
            urlQuery: loc.search,
            setUrlQuery(v) {
              history.replace(`${loc.pathname}?${v}`)
            }
          }}
        >
          {props.children}
        </UrlStateProvider>
      )
    }

    Adapter for react-router v6:

    import { useLocation, useNavigate } from 'react-router-dom'
    
    function ReactRouter6UrlStateProvider(props: { children: React.ReactNode }) {
      const loc = useLocation()
      const navigate = useNavigate()
    
      return (
        <UrlStateProvider
          value={{
            urlQuery: loc.search,
            setUrlQuery(v) {
              navigate(`${loc.pathname}?${v}`)
            }
          }}
        >
          {props.children}
        </UrlStateProvider>
      )
    }

    Step 2

    Define your own url state hook, use useUrlState() to get query, parse it manually, and set query.

    import { useUrlState } from '@baurine/use-url-state'
    
    type ExampleUrlState = Partial<Record<'count', string>>
    
    export function useExampleUrlState() {
      const [queryParams, setQueryParams] = useUrlState<ExampleUrlState>()
    
      // count
      const count = parseInt(queryParams.count ?? '')
      const setCount = (v?: string) => setQueryParams({ count: v })
    
      return { count, setCount }
    }

    Step 3

    Use the self defined url state hook in your logic code.

    import { useExampleUrlState } from './url-state'
    
    function CountButton() {
      const { count, setCount } = useExampleUrlState()
    
      return (
        <div className="card">
          Count: <button onClick={() => setCount('5')}>Init</button>{' '}
          {!isNaN(count) && (
            <>
              <button onClick={() => setCount(`${count + 1}`)}>Add</button>{' '}
              <button onClick={() => setCount(`${count - 1}`)}>Subtract</button>{' '}
            </>
          )}
          <button onClick={() => setCount()}>Clear</button>
        </div>
      )
    }
    
    function CountValue() {
      const { count } = useExampleUrlState()
    
      return <div className="card">Count is {count}</div>
    }
    
    export function Counter() {
      return (
        <div>
          <h2>@baurine/use-url-state demo</h2>
          <CountButton />
          <CountValue />
        </div>
      )
    }

    Demo

    https://github.com/user-attachments/assets/4efdca4b-e542-4af3-b090-44a64736915e