DEV Community

Saurav Pandey
Saurav Pandey

Posted on

Stop Fighting Your Router: Full URL Parsing in React with Zero Dependencies

How many times have you installed a massive routing framework just to parse a query parameter or generate a breadcrumb trail?

In lightweight React applications, embedding heavy-weight navigation packages just to read from window.location feels like overkill. Yet, writing your own state listeners to safely track dynamic changes—especially programmatic updates via history.pushState—is surprisingly complex and error-prone.

That is why we just introduced the useURL hook in the react-hook-lab library. It provides native, real-time, SSR-safe URL tracking and detailed analytical metadata with absolutely zero external dependencies.

Why Tracking the URL is Hard in Vanilla React

React doesn't natively watch the URL. The standard window.location object is not reactive; updating the search params or executing a history push does not trigger a re-render. Developers usually resort to:

  1. Listening to popstate (which misses programmatic routing like pushState/replaceState).
  2. Hooking into framework-specific routers (which locks your component into that specific ecosystem).
  3. Building brittle custom state syncs that often suffer from referential instability and infinite render loops.

useURL solves this cleanly by globally monkey-patching pushState and replaceState once, exposing a fully reactive, deeply parsed URL representation that works across any standard React app.


Code Example 1: Real-Time Search and Query Parameter Extraction

Extracting search queries and acting on them is as simple as reading an object. useURL automatically aggregates duplicate query parameters into clean arrays.

import React from 'react';
import { useURL } from 'react-hook-lab';

export function SearchInterface() {
  const { query, pathname } = useURL();

  // Safely parse single query parameters or lists
  const searchTerm = typeof query.q === 'string' ? query.q : '';
  const selectedFilters = Array.isArray(query.filter) 
    ? query.filter 
    : query.filter 
    ? [query.filter] 
    : [];

  return (
    <div style={{ padding: '16px', border: '1px solid #ccc' }}>
      <h3>Active Route: {pathname}</h3>
      <p>Search Term: <strong>{searchTerm || 'None'}</strong></p>
      <div>
        <span>Active Filters: </span>
        {selectedFilters.map((filter) => (
          <span key={filter} style={{ margin: '0 4px', background: '#ddd', padding: '2px 6px' }}>
            {filter}
          </span>
        ))}
      </div>
    </div>
  );
}
Enter fullscreen mode Exit fullscreen mode

Code Example 2: Automatic Breadcrumbs and Navigation History

useURL maintains a reference to your previous path, tracking whether the route changed in the current session and compiling progressive breadcrumbs on the fly.

import React from 'react';
import { useURL } from 'react-hook-lab';

export function DynamicBreadcrumbs() {
  const { breadcrumbs, previous, changed, timestamp } = useURL();

  return (
    <nav aria-label="breadcrumb" style={{ fontFamily: 'sans-serif' }}>
      <ol style={{ display: 'flex', listStyle: 'none', padding: 0 }}>
        {breadcrumbs.map((crumb, index) => (
          <li key={crumb.path} style={{ marginRight: '8px' }}>
            <a href={crumb.path}>{crumb.name}</a>
            {index < breadcrumbs.length - 1 && <span style={{ marginLeft: '8px' }}>/</span>}
          </li>
        ))}
      </ol>
      {changed && (
        <p style={{ fontSize: '12px', color: '#666' }}>
          You navigated here from <strong>{previous}</strong> at {new Date(timestamp).toLocaleTimeString()}.
        </p>
      )}
    </nav>
  );
}
Enter fullscreen mode Exit fullscreen mode

Comprehensive Features in useURL

Beyond basic pathnames and parameters, the return payload includes structural information:

  • filename & extension: Automatically parsed path targets (e.g., extracts report and pdf from /assets/report.pdf).
  • parent: Instantly determines the structural parent directory.
  • depth: Easily map hierarchical layout heights.
  • isSecure & isHome: Quick flags for security checks and index root logic.

Resources


Originally published on my blog. You can read the alternative breakdown here.

Top comments (0)