typescriptintermediate

useSearchParamsState Hook

Syncs component state with URL search parameters for shareable filter/sort states.

typescript
import { useState, useCallback, useEffect } from 'react';

export function useSearchParamsState<T extends string>(key: string, defaultValue: T): [T, (value: T) => void] {
  const [value, setValue] = useState<T>(() => {
    if (typeof window === 'undefined') return defaultValue;
    const params = new URLSearchParams(window.location.search);
    return (params.get(key) as T) || defaultValue;
  });

  const setParam = useCallback((newValue: T) => {
    setValue(newValue);
    const url = new URL(window.location.href);
    if (newValue === defaultValue) {
      url.searchParams.delete(key);
    } else {
      url.searchParams.set(key, newValue);
    }
    window.history.replaceState({}, '', url.toString());
  }, [key, defaultValue]);

  useEffect(() => {
    const handler = () => {
      const params = new URLSearchParams(window.location.search);
      setValue((params.get(key) as T) || defaultValue);
    };
    window.addEventListener('popstate', handler);
    return () => window.removeEventListener('popstate', handler);
  }, [key, defaultValue]);

  return [value, setParam];
}

Use Cases

  • Filter state persistence
  • Shareable search results

Tags

Related Snippets

Similar patterns you can reuse in the same workflow.