Understanding Parallel Routes in Next.js
Parallel routes in Next.js allow multiple pages to match the current URL, displayed within their respective layouts simultaneously. They enable a dynamic and persistent user experience while navigating through different sections of an application.
Implementing Parallel Routes
To use parallel routes:
- Rename Folders: Add an
@
prefix to folder names representing parallel routes (e.g.,@blog
,@shop
). - Update Layouts: In the layout file, include props matching folder names (e.g.,
blog
andshop
).
Here's an example layout:
import React from 'react';
export default function Layout({ children, blog, shop }) {
return (
<div>
<header>My App</header>
<main>
{children}
<section>{blog}</section>
<section>{shop}</section>
</main>
</div>
);
}
Benefits of Parallel Routes
- Built-In Error and Loading Handling: Pages can have
error.js
andloading.js
files for better user feedback during data fetching or error occurrences. Components require manual error boundaries andReact.Suspense
. - Static Optimization: Next.js optimizes pages for caching and static file generation if conditions are met. Components may not leverage this fully.
- State Persistence: Parallel routes maintain their state during soft navigations. This feature is particularly useful for multi-slot layouts.
Managing Persistent Slots
When navigating between pages, slots (e.g., blog
, shop
) remain active, ensuring layout consistency. However, if a hard refresh occurs and the slots aren’t in the current route, a 404 error appears. To handle this, create a default.tsx
file in the respective folders:
export default function DefaultPage() {
return null;
}
This ensures Next.js renders a fallback for slots not present in the active route.
Use Cases
Login Overlay Example
A login overlay can be implemented as a parallel route, blending seamlessly with the underlying page while maintaining the state of other sections.
// Layout example with slots
export default function Layout({ children, blog, shop }) {
return (
<div>
<nav>My App Navigation</nav>
<main>
{children}
<aside>{blog}</aside>
<aside>{shop}</aside>
</main>
</div>
);
}
// Login page
export default function Login() {
return (
<div className="login-overlay">
<h2>Login</h2>
<button onClick={() => router.back()}>Go Back</button>
</div>
);
}
The login overlay persists other slots (like blog
and shop
), and the URL updates to reflect the login route.
Tab Navigation Example
Tabs within a page can also benefit from parallel routes. Each tab represents a page, enabling state persistence across navigations.
// Blog layout with tabs
export default function BlogLayout({ children }) {
return (
<div>
<nav>
<a href="/blog/top-three">Top Three</a>
<a href="/blog/archive">Archive</a>
</nav>
<section>{children}</section>
</div>
);
}
Navigating between tabs like Top Three
and Archive
does not affect the state of other parallel routes, such as the shop
.
Advanced Usage: Loading and Error Handling
By creating loading.js
or error.js
files within the route folder, Next.js automatically handles asynchronous loading states or errors.
// loading.js
export default function Loading() {
return <p>Loading...</p>;
}
// Example of an async page
export default async function Shop() {
await new Promise((resolve) => setTimeout(resolve, 3000));
return <p>Shop content loaded!</p>;
}
When navigating to the Shop
route, the loading.js
component renders while the data loads.
Conclusion
Parallel routes in Next.js streamline the development of complex layouts with persistent slots, optimized rendering, and built-in error/loading handling. Use them to create cohesive and dynamic user experiences while leveraging Next.js's powerful features.