JAVASCRIPT

Sync React State with URL Query Parameters

Create a custom React hook to automatically synchronize component state with URL query parameters, allowing state to persist across refreshes and be shareable.

import { useState, useEffect, useCallback } from 'react';
import { useSearchParams, useNavigate } from 'react-router-dom'; // Assuming react-router-dom v6

function useUrlState(key, defaultValue) {
  const [searchParams, setSearchParams] = useSearchParams();
  const navigate = useNavigate(); // For potential programmatic navigation if needed

  const urlValue = searchParams.get(key);
  const [state, setState] = useState(() => {
    try {
      return urlValue ? JSON.parse(urlValue) : defaultValue;
    } catch (e) {
      console.error(`Error parsing URL parameter ${key}:`, e);
      return defaultValue;
    }
  });

  // Update URL whenever local state changes
  useEffect(() => {
    const newSearchParams = new URLSearchParams(searchParams.toString());
    if (state !== undefined && state !== null && state !== '') {
      try {
        newSearchParams.set(key, JSON.stringify(state));
      } catch (e) {
        console.error(`Error stringifying state for URL parameter ${key}:`, e);
        // Fallback or ignore
      }
    } else {
      newSearchParams.delete(key);
    }
    setSearchParams(newSearchParams, { replace: true });
  }, [key, state, searchParams, setSearchParams]);

  // Update local state when URL changes externally (e.g., back/forward button)
  useEffect(() => {
    const latestUrlValue = searchParams.get(key);
    try {
      const parsedUrlValue = latestUrlValue ? JSON.parse(latestUrlValue) : undefined;
      // Only update if the URL value is actually different from current state
      // This prevents infinite loops if state changes cause URL update, which then causes state update
      if (JSON.stringify(parsedUrlValue) !== JSON.stringify(state)) {
        setState(parsedUrlValue || defaultValue);
      }
    } catch (e) {
      console.error(`Error parsing URL parameter ${key} on external change:`, e);
      setState(defaultValue);
    }
  }, [key, searchParams, defaultValue, state]);


  // Memoize the setter to ensure stable reference
  const setUrlState = useCallback((newValue) => {
    setState(newValue);
  }, []);

  return [state, setUrlState];
}

export default useUrlState;
How it works: This custom hook `useUrlState` allows you to bind a component's state to a URL query parameter. It uses `useSearchParams` from `react-router-dom` to read and write values to the URL. The state is initialized from the URL, and any changes to the local state are automatically reflected in the URL. Conversely, changes to the URL (e.g., via browser navigation) will update the component's state, ensuring a persistent and shareable UI state.

Need help integrating this into your project?

Our team of expert developers can help you build your custom application from scratch.

Hire DigitalCodeLabs