Next.js useLocation Replacement: Migrating from React Router to next/navigation

Replace React Router's useLocation() hook by combining usePathname() and useSearchParams() from next/navigation, using useRouter() when you need programmatic navigation.

When migrating a React application to Next.js, you will need to adapt your routing logic to the App Router architecture. The next/navigation module provides granular hooks that together offer the same functionality as React Router's useLocation, but with better Server Component compatibility and optimized client-side performance.

Why Next.js Uses Separate Hooks Instead of useLocation

React Router's useLocation returns a monolithic location object containing pathname, search, hash, state, and key. Next.js deliberately splits these concerns across multiple hooks to support partial prerendering and React Server Components.

According to the source code in packages/next/src/client/components/navigation.ts, the navigation API exposes atomic hooks that read from specialized React contexts. This design allows components to subscribe only to the specific URL segments they need, preventing unnecessary re-renders when unrelated parts of the URL change.

The Equivalent Hooks in next/navigation

usePathname for Path Access

The usePathname hook returns the current URL pathname as a string. In packages/next/src/client/components/navigation.ts (lines 101-110), this hook reads from the PathnameContext provided by the App Router.

"use client";

import { usePathname } from "next/navigation";

export default function PagePath() {
  const pathname = usePathname(); // Returns "/dashboard/settings"
  
  return <div>Current path: {pathname}</div>;
}

useSearchParams for Query Strings

For search parameters, use useSearchParams, which returns a URLSearchParams instance. The implementation (lines 55-73 in navigation.ts) manages the query string state and provides reactive updates when parameters change.

"use client";

import { useSearchParams } from "next/navigation";

export default function SearchDisplay() {
  const searchParams = useSearchParams();
  const category = searchParams.get("category");
  
  return <div>Category: {category ?? "All"}</div>;
}

useRouter for Programmatic Navigation

When you need to navigate programmatically (equivalent to history.push or history.replace), use the useRouter hook. Lines 45-53 in navigation.ts define this hook, which provides methods like push(), replace(), and refresh().

"use client";

import { useRouter } from "next/navigation";

export default function NavigateButton() {
  const router = useRouter();
  
  const handleClick = () => {
    router.push("/dashboard?tab=analytics");
  };
  
  return <button onClick={handleClick}>Go to Dashboard</button>;
}

Complete Migration Examples

Reading the Full Location Object

To replicate const location = useLocation() from React Router, combine usePathname and useSearchParams:

"use client";

import { usePathname, useSearchParams } from "next/navigation";

export default function LocationDisplay() {
  const pathname = usePathname();
  const searchParams = useSearchParams();
  
  const search = searchParams.toString();
  const fullUrl = `${pathname}${search ? `?${search}` : ""}`;
  
  return (
    <div>
      <p>Pathname: {pathname}</p>
      <p>Search: {search}</p>
      <p>Full URL: {fullUrl}</p>
    </div>
  );
}

Creating a Custom useLocation Hook

For drop-in compatibility during migration, wrap the Next.js hooks to match React Router's API:

"use client";

import { usePathname, useSearchParams } from "next/navigation";

export function useLocation() {
  const pathname = usePathname();
  const searchParams = useSearchParams();
  
  return {
    pathname,
    search: searchParams.toString() ? `?${searchParams.toString()}` : "",
    // Hash must be accessed from window.location as Next.js doesn't expose it
    hash: typeof window !== "undefined" ? window.location.hash : "",
    // Note: state is not supported; use React context or URL parameters instead
  };
}

Key Source Files in the Repository

The Next.js navigation system relies on these core files in the vercel/next.js repository:

Summary

  • Replace useLocation().pathname with usePathname() from next/navigation.
  • Replace useLocation().search with useSearchParams() which returns a URLSearchParams object.
  • Use useRouter() for programmatic navigation instead of history.push or history.replace.
  • No direct equivalent exists for location.hash or location.state; access hash via window.location and manage state through React context or URL parameters.
  • All navigation hooks require the "use client" directive and work exclusively in the App Router.

Frequently Asked Questions

How do I access the URL hash in Next.js?

Next.js does not expose the URL hash through next/navigation hooks because the hash is not sent to the server. Access it client-side using window.location.hash inside a useEffect or check typeof window !== "undefined" to prevent hydration mismatches.

What replaces location.state from React Router?

Next.js does not implement location.state for the App Router. Store temporary navigation state using React Context, URL search parameters, or browser APIs like sessionStorage before navigating with router.push().

Can I use these hooks in Server Components?

No, usePathname, useSearchParams, and useRouter are client-side only and require the "use client" directive. In Server Components, access URL data through searchParams props passed to page components or use headers() and cookies() from next/headers for server-side URL inspection.

Is useRouter from next/navigation different from next/router?

Yes, useRouter from next/navigation is specifically for the App Router and provides methods like push(), replace(), and refresh(). The useRouter from next/router is for the legacy Pages Router and has a different API. Always import from next/navigation when using the App Router.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →