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:
packages/next/src/client/components/navigation.ts– Contains the primary hook implementations (usePathname,useSearchParams,useRouter) that read from internal contexts.packages/next/src/shared/lib/hooks-client-context.shared-runtime.ts– Provides the React contexts that supply pathname and search parameter data to the hooks.packages/next/src/shared/lib/app-router-context.shared-runtime.ts– Defines theAppRouterContextused byuseRouterto access navigation methods.
Summary
- Replace
useLocation().pathnamewithusePathname()fromnext/navigation. - Replace
useLocation().searchwithuseSearchParams()which returns aURLSearchParamsobject. - Use
useRouter()for programmatic navigation instead ofhistory.pushorhistory.replace. - No direct equivalent exists for
location.hashorlocation.state; access hash viawindow.locationand 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:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →