2024-10-19 Web Development

Next.js: Navigating Between Routes

By O. Wolfson

Currently Reading: Linking and Navigation, from the Next.js Docs.

Next.js offers multiple ways to navigate between routes, which can improve the user experience by speeding up page transitions and preserving state. Here’s a quick guide to the most common methods:

1. <Link> Component

The <Link> component is Next.js's recommended way to navigate between pages. It extends the HTML <a> tag to include prefetching and client-side navigation.

Example:

jsx
import Link from "next/link";

export default function Page() {
  return <Link href="/dashboard">Go to Dashboard</Link>;
}

When you use <Link>, Next.js automatically prefetches the linked page in the background, enhancing performance.

2. useRouter() Hook

The useRouter() hook gives you programmatic control over navigation within Client Components. It’s great when you want to trigger navigation based on some logic (e.g., after a form submission).

Example:

jsx
"use client";

import { useRouter } from "next/navigation";

export default function Page() {
  const router = useRouter();

  return (
    <button onClick={() => router.push("/dashboard")}>Go to Dashboard</button>
  );
}

3. redirect() Function

For Server Components, you can use the redirect() function to change routes, especially after fetching some data or handling server logic.

Example:

ts
import { redirect } from "next/navigation";

export default async function Profile({ params }) {
  const team = await fetchTeam(params.id);
  if (!team) {
    redirect("/login");
  }

  // Render profile if the team exists
}

This is particularly useful in server actions or when redirecting users based on server-side data.

4. Native History API

Next.js allows you to use the native browser history methods, pushState and replaceState. These are useful for updating the URL without triggering a full page reload.

Example (Sorting Products):

jsx
"use client";

export default function SortProducts() {
  function updateSorting(order) {
    const params = new URLSearchParams(window.location.search);
    params.set("sort", order);
    window.history.pushState(null, "", `?${params.toString()}`);
  }

  return (
    <div>
      <button onClick={() => updateSorting("asc")}>Sort Ascending</button>
      <button onClick={() => updateSorting("desc")}>Sort Descending</button>
    </div>
  );
}

This approach is more manual and gives you fine control over the browser's history stack.

How Navigation Works in Next.js

Next.js optimizes navigation performance by combining client-side techniques and server capabilities:

1. Code Splitting

Next.js automatically splits your code into smaller chunks by route. This reduces the amount of code downloaded during navigation, leading to faster page loads.

2. Prefetching

By default, Next.js preloads routes when they appear in the viewport or when the page is loaded, improving page load times on navigation.

3. Caching

Next.js uses a client-side cache to store prefetched route segments, which reduces the need for repeated server requests during navigation.

4. Partial Rendering

When you navigate between sibling routes (e.g., /dashboard/settings and /dashboard/analytics), only the changing parts of the page are rendered. The shared layout remains the same, leading to faster transitions.

5. Soft Navigation

Next.js enables "soft navigation," where only the necessary route segments are re-rendered, preserving React state and improving performance.

6. Back and Forward Navigation

Next.js automatically maintains the scroll position and reuses cached route segments when navigating backwards and forwards in the browser.

Conclusion

Next.js offers multiple navigation tools for various scenarios:

  • Use <Link> for standard client-side navigation.
  • Use useRouter() for programmatic navigation in Client Components.
  • Use redirect() in Server Components for server-side redirects.
  • Use the native history API when fine control over the URL is needed without reloading the page.

Each of these tools is designed to optimize performance and improve the user experience by minimizing page reloads and leveraging Next.js’s built-in caching and prefetching capabilities.