1:"$Sreact.fragment" 2:I[79520,["/_next/static/chunks/0sqf3kwsxhw92.js","/_next/static/chunks/15vvi4du_kj4d.js","/_next/static/chunks/0t2xr05rlu96l.js","/_next/static/chunks/0j_00-43ohwi..js","/_next/static/chunks/074m5~1.spxnd.js"],""] 4:I[11414,["/_next/static/chunks/0sqf3kwsxhw92.js","/_next/static/chunks/15vvi4du_kj4d.js","/_next/static/chunks/0t2xr05rlu96l.js","/_next/static/chunks/0j_00-43ohwi..js","/_next/static/chunks/074m5~1.spxnd.js"],"Providers"] 5:I[62319,["/_next/static/chunks/0sqf3kwsxhw92.js","/_next/static/chunks/15vvi4du_kj4d.js","/_next/static/chunks/0t2xr05rlu96l.js","/_next/static/chunks/0j_00-43ohwi..js","/_next/static/chunks/074m5~1.spxnd.js"],"Navbar"] 6:I[39756,["/_next/static/chunks/0sqf3kwsxhw92.js","/_next/static/chunks/15vvi4du_kj4d.js","/_next/static/chunks/0t2xr05rlu96l.js","/_next/static/chunks/0j_00-43ohwi..js","/_next/static/chunks/074m5~1.spxnd.js"],"default"] 7:I[8821,["/_next/static/chunks/0sqf3kwsxhw92.js","/_next/static/chunks/15vvi4du_kj4d.js","/_next/static/chunks/0t2xr05rlu96l.js","/_next/static/chunks/0j_00-43ohwi..js","/_next/static/chunks/074m5~1.spxnd.js","/_next/static/chunks/0mz45ejphoh5z.js"],"default"] 8:I[37457,["/_next/static/chunks/0sqf3kwsxhw92.js","/_next/static/chunks/15vvi4du_kj4d.js","/_next/static/chunks/0t2xr05rlu96l.js","/_next/static/chunks/0j_00-43ohwi..js","/_next/static/chunks/074m5~1.spxnd.js"],"default"] 11:I[53348,["/_next/static/chunks/0sqf3kwsxhw92.js","/_next/static/chunks/15vvi4du_kj4d.js","/_next/static/chunks/0t2xr05rlu96l.js","/_next/static/chunks/0j_00-43ohwi..js","/_next/static/chunks/074m5~1.spxnd.js","/_next/static/chunks/0~5g53tt668k4.js"],"default"] :HL["/_next/static/chunks/0yx0yo5_jwh4r.css","style"] :HL["/_next/static/media/83afe278b6a6bb3c-s.p.0q-301v4kxxnr.woff2","font",{"crossOrigin":"","type":"font/woff2"}] 3:T5e1,[{"@context":"https://schema.org","@type":"Person","name":"Muhammad Zaid","jobTitle":"Python Developer & Backend Engineer","description":"Full-stack developer specializing in Python backend, web scraping, automation, and cybersecurity","url":"https://zaid.sh","knowsAbout":["Python","Django","FastAPI","Web Scraping","Automation","Cybersecurity","Pentesting"],"sameAs":["https://github.com/zaidkx37","https://linkedin.com/in/zaidkx37","https://www.upwork.com/freelancers/~01aaf487e29d60a885"]},{"@context":"https://schema.org","@type":"SoftwareApplication","name":"tubescrape","description":"A fast, lightweight Python toolkit for scraping YouTube without an API key","author":{"@type":"Person","name":"Muhammad Zaid"},"applicationCategory":"DeveloperApplication","operatingSystem":"Cross-platform","url":"https://pypi.org/project/tubescrape/"},{"@context":"https://schema.org","@type":"SoftwareApplication","name":"shopscout","description":"Scrape any Shopify store from the public JSON API","author":{"@type":"Person","name":"Muhammad Zaid"},"applicationCategory":"DeveloperApplication","operatingSystem":"Cross-platform","url":"https://pypi.org/project/shopscout/"},{"@context":"https://schema.org","@type":"SoftwareApplication","name":"wpscrape","description":"Scrape any WordPress/WooCommerce store from the public REST API","author":{"@type":"Person","name":"Muhammad Zaid"},"applicationCategory":"DeveloperApplication","operatingSystem":"Cross-platform","url":"https://pypi.org/project/wpscrape/"}]0:{"P":null,"c":["","blog","nextjs-navigation-fix"],"q":"","i":false,"f":[[["",{"children":["blog",{"children":[["slug","nextjs-navigation-fix","d",null],{"children":["__PAGE__",{}]}]}]},"$undefined","$undefined",16],[["$","$1","c",{"children":[[["$","link","0",{"rel":"stylesheet","href":"/_next/static/chunks/0yx0yo5_jwh4r.css","precedence":"next","crossOrigin":"$undefined","nonce":"$undefined"}],["$","script","script-0",{"src":"/_next/static/chunks/0sqf3kwsxhw92.js","async":true,"nonce":"$undefined"}],["$","script","script-1",{"src":"/_next/static/chunks/15vvi4du_kj4d.js","async":true,"nonce":"$undefined"}],["$","script","script-2",{"src":"/_next/static/chunks/0t2xr05rlu96l.js","async":true,"nonce":"$undefined"}],["$","script","script-3",{"src":"/_next/static/chunks/0j_00-43ohwi..js","async":true,"nonce":"$undefined"}],["$","script","script-4",{"src":"/_next/static/chunks/074m5~1.spxnd.js","async":true,"nonce":"$undefined"}]],["$","html",null,{"lang":"en","suppressHydrationWarning":true,"children":[["$","head",null,{"children":[["$","$L2",null,{"src":"https://www.googletagmanager.com/gtag/js?id=G-ETY86N5E6J","strategy":"afterInteractive"}],["$","$L2",null,{"id":"google-analytics","strategy":"afterInteractive","children":"window.dataLayer = window.dataLayer || [];\n function gtag(){dataLayer.push(arguments);}\n gtag('js', new Date());\n gtag('config', 'G-ETY86N5E6J');"}],["$","script",null,{"type":"application/ld+json","dangerouslySetInnerHTML":{"__html":"$3"}}]]}],["$","body",null,{"className":"inter_5972bc34-module__OU16Qa__className","children":["$","$L4",null,{"children":[["$","$L5",null,{}],["$","main",null,{"children":["$","$L6",null,{"parallelRouterKey":"children","error":"$7","errorStyles":[],"errorScripts":[["$","script","script-0",{"src":"/_next/static/chunks/0mz45ejphoh5z.js","async":true}]],"template":["$","$L8",null,{}],"templateStyles":"$undefined","templateScripts":"$undefined","notFound":[["$","div",null,{"className":"min-h-screen bg-background text-foreground flex items-center justify-center px-4","children":["$","div",null,{"className":"max-w-2xl w-full text-center space-y-8","children":[["$","div",null,{"className":"relative","children":[["$","h1",null,{"className":"text-[150px] md:text-[200px] font-bold leading-none","children":["$","span",null,{"className":"bg-clip-text text-transparent bg-gradient-to-r from-primary to-primary/70","children":"404"}]}],["$","div",null,{"className":"absolute inset-0 bg-gradient-to-r from-primary/20 to-primary/10 blur-3xl -z-10"}]]}],"$L9","$La"]}]}],[]],"forbidden":"$undefined","unauthorized":"$undefined"}]}],"$Lb"]}]}]]}]]}],{"children":["$Lc",{"children":["$Ld",{"children":["$Le",{},null,false,null]},null,false,"$@f"]},null,false,"$@f"]},null,false,null],"$L10",false]],"m":"$undefined","G":["$11",["$L12"]],"S":true,"h":null,"s":"$undefined","l":"$undefined","p":"$undefined","d":"$undefined","b":"QX83e4YaSJMU9KhrDXtKJ"} 13:I[22016,["/_next/static/chunks/0sqf3kwsxhw92.js","/_next/static/chunks/15vvi4du_kj4d.js","/_next/static/chunks/0t2xr05rlu96l.js","/_next/static/chunks/0j_00-43ohwi..js","/_next/static/chunks/074m5~1.spxnd.js","/_next/static/chunks/03pwh54kk_crp.js"],""] 14:I[56691,["/_next/static/chunks/0sqf3kwsxhw92.js","/_next/static/chunks/15vvi4du_kj4d.js","/_next/static/chunks/0t2xr05rlu96l.js","/_next/static/chunks/0j_00-43ohwi..js","/_next/static/chunks/074m5~1.spxnd.js"],"Footer"] 16:I[97367,["/_next/static/chunks/0sqf3kwsxhw92.js","/_next/static/chunks/15vvi4du_kj4d.js","/_next/static/chunks/0t2xr05rlu96l.js","/_next/static/chunks/0j_00-43ohwi..js","/_next/static/chunks/074m5~1.spxnd.js"],"OutletBoundary"] 17:"$Sreact.suspense" 1a:I[97367,["/_next/static/chunks/0sqf3kwsxhw92.js","/_next/static/chunks/15vvi4du_kj4d.js","/_next/static/chunks/0t2xr05rlu96l.js","/_next/static/chunks/0j_00-43ohwi..js","/_next/static/chunks/074m5~1.spxnd.js"],"ViewportBoundary"] 1c:I[97367,["/_next/static/chunks/0sqf3kwsxhw92.js","/_next/static/chunks/15vvi4du_kj4d.js","/_next/static/chunks/0t2xr05rlu96l.js","/_next/static/chunks/0j_00-43ohwi..js","/_next/static/chunks/074m5~1.spxnd.js"],"MetadataBoundary"] 9:["$","div",null,{"className":"space-y-4","children":[["$","h2",null,{"className":"text-3xl md:text-4xl font-bold tracking-tighter","children":"Page Not Found"}],["$","p",null,{"className":"text-lg text-muted-foreground max-w-md mx-auto","children":"Oops! The page you're looking for doesn't exist. It might have been moved or deleted."}]]}] a:["$","div",null,{"className":"flex flex-col sm:flex-row gap-4 justify-center items-center pt-4","children":["$","$L13",null,{"href":"/","className":"inline-flex items-center justify-center rounded-full bg-gradient-to-r from-[#0EA5E9] to-[#9b87f5] hover:from-[#33C3F0] hover:to-[#7E69AB] shadow-lg shadow-primary/20 text-white px-8 py-3 font-medium","children":"Back to Home"}]}] b:["$","$L14",null,{}] c:["$","$1","c",{"children":[null,["$","$L6",null,{"parallelRouterKey":"children","error":"$undefined","errorStyles":"$undefined","errorScripts":"$undefined","template":["$","$L8",null,{}],"templateStyles":"$undefined","templateScripts":"$undefined","notFound":"$undefined","forbidden":"$undefined","unauthorized":"$undefined"}]]}] d:["$","$1","c",{"children":[null,["$","$L6",null,{"parallelRouterKey":"children","error":"$undefined","errorStyles":"$undefined","errorScripts":"$undefined","template":["$","$L8",null,{}],"templateStyles":"$undefined","templateScripts":"$undefined","notFound":"$undefined","forbidden":"$undefined","unauthorized":"$undefined"}]]}] e:["$","$1","c",{"children":["$L15",[["$","script","script-0",{"src":"/_next/static/chunks/03pwh54kk_crp.js","async":true,"nonce":"$undefined"}]],["$","$L16",null,{"children":["$","$17",null,{"name":"Next.MetadataOutlet","children":"$@18"}]}]]}] 19:[] f:"$W19" 10:["$","$1","h",{"children":[null,["$","$L1a",null,{"children":"$L1b"}],["$","div",null,{"hidden":true,"children":["$","$L1c",null,{"children":["$","$17",null,{"name":"Next.Metadata","children":"$L1d"}]}]}],["$","meta",null,{"name":"next-size-adjust","content":""}]]}] 12:["$","link","0",{"rel":"stylesheet","href":"/_next/static/chunks/0yx0yo5_jwh4r.css","precedence":"next","crossOrigin":"$undefined","nonce":"$undefined"}] 15:["$","div",null,{"className":"min-h-screen bg-background text-foreground","children":[["$","section",null,{"className":"pt-28 pb-16 md:pt-36 md:pb-24 bg-gradient-to-b from-accent/30 to-background","children":["$","div",null,{"className":"container px-4 md:px-6","children":["$","div",null,{"className":"max-w-4xl mx-auto","children":[["$","$L13",null,{"href":"/blog","children":[["$","svg",null,{"ref":"$undefined","xmlns":"http://www.w3.org/2000/svg","width":24,"height":24,"viewBox":"0 0 24 24","fill":"none","stroke":"currentColor","strokeWidth":2,"strokeLinecap":"round","strokeLinejoin":"round","className":"lucide lucide-arrow-left mr-2 h-4 w-4","children":[["$","path","1l729n",{"d":"m12 19-7-7 7-7"}],["$","path","x3x0zl",{"d":"M19 12H5"}],"$undefined"]}],"Back to Blog"],"className":"inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0 hover:bg-accent hover:text-accent-foreground h-10 px-4 py-2 mb-6","ref":null}],["$","div",null,{"className":"inline-flex items-center rounded-full border px-2.5 py-0.5 text-xs font-semibold transition-colors focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 border-transparent bg-primary text-primary-foreground hover:bg-primary/80 mb-4","children":"Frontend"}],["$","h1",null,{"className":"text-3xl md:text-4xl lg:text-5xl font-bold tracking-tighter mb-6 animate-fade-in","children":"How I Finally Fixed the Slow Navigation in Next.js App Router"}],["$","div",null,{"className":"flex flex-wrap items-center gap-4 text-muted-foreground mb-8 animate-fade-in","children":[["$","div",null,{"className":"flex items-center gap-2","children":[["$","svg",null,{"ref":"$undefined","xmlns":"http://www.w3.org/2000/svg","width":24,"height":24,"viewBox":"0 0 24 24","fill":"none","stroke":"currentColor","strokeWidth":2,"strokeLinecap":"round","strokeLinejoin":"round","className":"lucide lucide-calendar h-4 w-4","children":[["$","path","1cmpym",{"d":"M8 2v4"}],["$","path","4m81vk",{"d":"M16 2v4"}],["$","rect","1hopcy",{"width":"18","height":"18","x":"3","y":"4","rx":"2"}],["$","path","8toen8",{"d":"M3 10h18"}],"$undefined"]}],["$","span",null,{"children":"December 23, 2024"}]]}],["$","div",null,{"className":"flex items-center gap-2","children":[["$","svg",null,{"ref":"$undefined","xmlns":"http://www.w3.org/2000/svg","width":24,"height":24,"viewBox":"0 0 24 24","fill":"none","stroke":"currentColor","strokeWidth":2,"strokeLinecap":"round","strokeLinejoin":"round","className":"lucide lucide-clock h-4 w-4","children":[["$","circle","1mglay",{"cx":"12","cy":"12","r":"10"}],["$","polyline","68esgv",{"points":"12 6 12 12 16 14"}],"$undefined"]}],["$","span",null,{"children":"10 min read"}]]}],["$","div",null,{"className":"flex items-center gap-2","children":["$","span",null,{"children":["By ","Muhammad Zaid"]}]}]]}],["$","div",null,{"className":"flex flex-wrap gap-2 mb-8 animate-fade-in","children":[["$","div","Next.js",{"className":"inline-flex items-center rounded-full border px-2.5 py-0.5 text-xs font-semibold transition-colors focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 text-foreground","children":"Next.js"}],["$","div","React",{"className":"inline-flex items-center rounded-full border px-2.5 py-0.5 text-xs font-semibold transition-colors focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 text-foreground","children":"React"}],["$","div","TypeScript",{"className":"inline-flex items-center rounded-full border px-2.5 py-0.5 text-xs font-semibold transition-colors focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 text-foreground","children":"TypeScript"}],["$","div","Web Development",{"className":"inline-flex items-center rounded-full border px-2.5 py-0.5 text-xs font-semibold transition-colors focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 text-foreground","children":"Web Development"}]]}]]}]}]}],"$L1e","$L1f","$L20"]}] 21:I[6966,["/_next/static/chunks/0sqf3kwsxhw92.js","/_next/static/chunks/15vvi4du_kj4d.js","/_next/static/chunks/0t2xr05rlu96l.js","/_next/static/chunks/0j_00-43ohwi..js","/_next/static/chunks/074m5~1.spxnd.js","/_next/static/chunks/03pwh54kk_crp.js"],"BlogPostContent"] 1e:["$","section",null,{"className":"pb-12","children":["$","div",null,{"className":"container px-4 md:px-6","children":["$","div",null,{"className":"max-w-4xl mx-auto","children":["$","img",null,{"src":"https://images.unsplash.com/photo-1555066931-4365d14bab8c?auto=format&fit=crop&w=800","alt":"How I Finally Fixed the Slow Navigation in Next.js App Router","className":"w-full h-auto rounded-lg shadow-xl","loading":"lazy"}]}]}]}] 22:T2289,# How I Finally Fixed the Slow Navigation in Next.js App Router (And You Can Too!) If you're reading this, chances are you've experienced that annoying lag when clicking links in your Next.js App Router application. You know what I'm talking about - that frustrating moment when you click a navigation link and... nothing happens. You wait. Still nothing. Then suddenly, boom - the page changes. Yeah, I've been there too. And honestly? It was driving me crazy. ## The Problem That Kept Me Up at Night I recently migrated one of my projects to Next.js 15 with the App Router, and while I loved all the new features - server components, improved data fetching, better performance - there was this one thing that kept bugging me: **the navigation felt sluggish**. Coming from the world of SPAs (Single Page Applications), I was used to instant feedback. Click a link, see it highlighted immediately, page transitions smooth as butter. But with the App Router, there was this weird limbo period between clicking a link and actually seeing any visual feedback. I started Googling. "Next.js slow navigation", "App Router navigation lag", "Next.js navigation feels slow" - you name it, I searched it. And you know what? I wasn't alone. Tons of developers were complaining about the same issue. ## Why Does This Happen? Here's the thing: the App Router relies heavily on server-side rendering (SSR) and static site generation (SSG). While this is great for performance and SEO, it means Next.js has to wait for the server to process the request before updating the UI. During this waiting period: - The link doesn't show an active state - The current content just sits there, looking stale - Users (like me) keep clicking, wondering if the app is broken - The experience feels janky and unresponsive Even worse, the navigation hooks like `usePathname` and `useSearchParams` only update **after** the navigation completes. So you can't even use them to show a loading state or highlight the active link immediately. ## The Search for a Solution I tried different approaches: - Added loading.js files (helped, but didn't solve the instant feedback issue) - Experimented with Suspense boundaries (same story) - Attempted client-side state management with onClick events (worked, but had edge cases like Cmd+Click to open in new tab) Nothing felt quite right. Until I stumbled upon Next.js 15.3 release notes and saw two game-changing features: 1. **`onNavigate` event** - fires when navigation starts, only on client-side 2. **`useOptimistic` hook** - allows optimistic UI updates And that's when it clicked. I could combine these to create instant, snappy navigation! ## The Solution That Actually Works Here's what I built, and trust me, it's simpler than you might think. ### Step 1: Create a Navigation Context First, I created a context to manage the optimistic navigation state across my entire app: ```tsx // contexts/OptimisticNavigationContext.tsx "use client"; import { usePathname } from "next/navigation"; import { createContext, ReactNode, useContext, useOptimistic } from "react"; type OptimisticNavigationContextType = { isNavigating: boolean; optimisticPathname: string; setOptimisticPathname: (pathname: string) => void; }; const OptimisticNavigationContext = createContext< OptimisticNavigationContextType | undefined >(undefined); export const OptimisticNavigationContextProvider = ({ children, }: { children: ReactNode; }) => { const pathname = usePathname(); const [optimisticPathname, setOptimisticPathname] = useOptimistic( pathname, (_, action: string) => action ); return ( {children} ); }; export const useOptimisticNavigation = () => { const context = useContext(OptimisticNavigationContext); if (!context) { throw new Error( "useOptimisticNavigation must be used within a OptimisticNavigationContextProvider" ); } return context; }; ``` The magic here is `useOptimistic`. It tracks two states: - `pathname` - the actual current path (from Next.js) - `optimisticPathname` - where we think we're going When they differ, we know navigation is in progress! ### Step 2: Wrap Your App Next, I wrapped my entire app with this context provider in the root layout: ```tsx // app/layout.tsx import { OptimisticNavigationContextProvider } from '@/contexts/OptimisticNavigationContext'; export default function RootLayout({ children, }: { children: React.ReactNode; }) { return ( {children} ); } ``` ### Step 3: Update Your Navigation Links This is where the real magic happens. In my Header component, I updated the links to use the new `onNavigate` event: ```tsx // components/Header.tsx "use client"; import Link from 'next/link'; import { startTransition } from 'react'; import { useOptimisticNavigation } from '@/contexts/OptimisticNavigationContext'; export default function Header() { const { optimisticPathname, setOptimisticPathname } = useOptimisticNavigation(); return ( ); } ``` **Important gotcha I discovered:** You MUST wrap `setOptimisticPathname` in `startTransition()`. Otherwise, you'll get an error about optimistic updates happening outside a transition. Learned that one the hard way! ### Step 4: Add Loading States (Bonus!) Want to show a loading indicator while navigating? Super easy now: ```tsx // components/NavigationWrapper.tsx "use client"; import { useOptimisticNavigation } from '@/contexts/OptimisticNavigationContext'; export default function NavigationWrapper({ children, className = '' }: { children: React.ReactNode; className?: string; }) { const { isNavigating } = useOptimisticNavigation(); return (
{children}
); } ``` Wrap any component with this, and it'll fade out during navigation. Clean and simple. ## The Results After implementing this solution, the difference was night and day: ✅ **Instant feedback** - Links highlight immediately when clicked ✅ **Better UX** - Users know their click registered ✅ **Loading states** - Can show spinners or fade effects anywhere ✅ **Handles edge cases** - Works with Cmd/Ctrl+Click, middle mouse button, etc. ✅ **Feels like an SPA** - Fast, responsive, exactly what I wanted ## Important Notes & Gotchas **1. Always use `startTransition`** Don't forget to wrap your optimistic updates in `startTransition()`, or React will yell at you. **2. This works with pathnames only** If you're using query parameters in your navigation, you'll need to extend the solution to track those too. **3. Requires Next.js 15.3+** The `onNavigate` event is only available in Next.js 15.3 and above. Make sure you're updated! **4. Client components only** The `useOptimistic` hook and `onNavigate` event only work in client components. But that's fine - just mark your navigation components with `"use client"`. ## Wrapping Up Honestly, this solution has been a game-changer for my Next.js projects. The navigation finally feels as snappy as it should, and my users have stopped complaining about the "broken" links. If you're struggling with slow navigation in Next.js App Router, give this approach a try. It might just save your sanity like it saved mine. Got questions or improvements? Drop them in the comments below. And if this helped you, consider sharing it with other developers fighting the same battle! Happy coding! 🚀 --- *P.S. - Big shoutout to the Next.js team for adding the `onNavigate` event. This is exactly the kind of DX improvement that makes framework updates exciting.*1f:["$","section",null,{"className":"pb-16","children":["$","div",null,{"className":"container px-4 md:px-6","children":["$","div",null,{"className":"max-w-4xl mx-auto","children":["$","article",null,{"className":"prose prose-lg dark:prose-invert max-w-none prose-pre:p-0 prose-pre:bg-transparent prose-pre:border-0","children":["$","$L21",null,{"content":"$22"}]}]}]}]}] 20:["$","section",null,{"className":"section bg-accent/30","children":["$","div",null,{"className":"container px-4 md:px-6","children":["$","div",null,{"className":"max-w-3xl mx-auto text-center space-y-6","children":[["$","h2",null,{"className":"text-3xl md:text-4xl font-bold tracking-tighter","children":["Need Expert ",["$","span",null,{"className":"text-primary","children":"Python Development"}],"?"]}],["$","p",null,{"className":"text-xl text-muted-foreground","children":["Looking to ",["$","strong",null,{"children":"hire Python developer"}]," or need help with ",["$","strong",null,{"children":"Django"}],", ",["$","strong",null,{"children":"web scraping"}],", or ",["$","strong",null,{"children":"automation"}],"projects? Let's work together!"]}],["$","div",null,{"className":"flex flex-col sm:flex-row gap-4 justify-center","children":[["$","$L13",null,{"href":"/contact","children":["Get In Touch ",["$","svg",null,{"ref":"$undefined","xmlns":"http://www.w3.org/2000/svg","width":24,"height":24,"viewBox":"0 0 24 24","fill":"none","stroke":"currentColor","strokeWidth":2,"strokeLinecap":"round","strokeLinejoin":"round","className":"lucide lucide-arrow-right ml-2 h-5 w-5","children":[["$","path","1ays0h",{"d":"M5 12h14"}],["$","path","xquz4c",{"d":"m12 5 7 7-7 7"}],"$undefined"]}]],"className":"inline-flex items-center justify-center gap-2 whitespace-nowrap text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0 bg-primary text-primary-foreground hover:bg-primary/90 h-11 px-8 rounded-full","ref":null}],["$","$L13",null,{"href":"/blog","children":"View All Posts","className":"inline-flex items-center justify-center gap-2 whitespace-nowrap text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0 border border-input bg-background hover:bg-accent hover:text-accent-foreground h-11 px-8 rounded-full","ref":null}]]}]]}]}]}] 1b:[["$","meta","0",{"charSet":"utf-8"}],["$","meta","1",{"name":"viewport","content":"width=device-width, initial-scale=1"}]] 18:null 1d:[["$","title","0",{"children":"How I Finally Fixed the Slow Navigation in Next.js App Router | Muhammad Zaid"}],["$","meta","1",{"name":"description","content":"Struggling with slow, laggy navigation in Next.js App Router? Learn how to use the new onNavigate event and useOptimistic hook to create instant, snappy navigation that feels like a true SPA."}],["$","meta","2",{"name":"author","content":"Muhammad Zaid"}],["$","meta","3",{"name":"keywords","content":"Muhammad Zaid,Python Developer,Python Engineer,Backend Developer,Full Stack Developer,Web Scraping Expert,Automation Specialist,Django Developer,FastAPI Developer,Cybersecurity Researcher,Pentesting,Upwork Freelancer"}],["$","meta","4",{"name":"creator","content":"Muhammad Zaid"}],["$","link","5",{"rel":"canonical","href":"https://zaid.sh/blog/nextjs-navigation-fix"}],["$","meta","6",{"name":"google-site-verification","content":"CXGpI1P1JjSh6uXJQFppKHX3vQkdJm0x45dQKyAd3bo"}],["$","meta","7",{"property":"og:title","content":"How I Finally Fixed the Slow Navigation in Next.js App Router"}],["$","meta","8",{"property":"og:description","content":"Struggling with slow, laggy navigation in Next.js App Router? Learn how to use the new onNavigate event and useOptimistic hook to create instant, snappy navigation that feels like a true SPA."}],["$","meta","9",{"property":"og:image","content":"https://images.unsplash.com/photo-1555066931-4365d14bab8c?auto=format&fit=crop&w=800"}],["$","meta","10",{"property":"og:type","content":"article"}],["$","meta","11",{"name":"twitter:card","content":"summary_large_image"}],["$","meta","12",{"name":"twitter:title","content":"Muhammad Zaid - Python Developer & Backend Engineer"}],["$","meta","13",{"name":"twitter:description","content":"Backend developer specializing in Python, web scraping, automation, and cybersecurity."}],["$","meta","14",{"name":"twitter:image","content":"https://images.unsplash.com/photo-1555066931-4365d14bab8c?auto=format&fit=crop&w=800"}]]