Async Router for NextJS 14+
Overcoming Challenges After Next.js Removed Async Router
When Next.js removed the async router API, it introduced unexpected challenges for developers like me. Managing navigation alongside asynchronous tasks became trickier, affecting smooth transitions and user experience. Here’s how I tackled it with a custom hook.
The Problem
The lack of async router support made it difficult to:
领英推荐
My Solution: useAsyncRouter
To solve these issues, I built a custom hook that reintroduces async behavior to navigation methods. It’s based on useRouter and React’s useTransition, allowing for seamless integration and better control over transitions.
'use client'
import { useRouter } from 'next/navigation'
import { useEffect, useTransition } from 'react'
// Define types for the observer and router
type ObserverCallback = () => void
type RouterFunction = (...args: any[]) => void
// Create route observer singleton
const createRouteObserver = () => {
let observer: ObserverCallback | null = null
const setObserver = (callback: ObserverCallback) => {
observer = callback
}
const notify = () => {
if (observer) {
observer()
}
}
return { setObserver, notify }
}
const routeObserver = createRouteObserver()
// Generic function to wrap router methods with async behavior
const createAsyncRouterMethod = (
routerFn: RouterFunction,
startTransition: (callback: () => void) => void
) => {
return async (...args: any[]) => {
return new Promise<void>((resolve) => {
startTransition(() => {
routerFn(...args)
})
routeObserver.setObserver(() => {
resolve()
})
})
}
}
export const useAsyncRouter = () => {
const [isPending, startTransition] = useTransition()
const router = useRouter()
// Create async versions of router methods
const push = createAsyncRouterMethod(
(path: string) => router.push(path),
startTransition
)
const refresh = createAsyncRouterMethod(
() => router.refresh(),
startTransition
)
const replace = createAsyncRouterMethod(
(path: string) => router.replace(path),
startTransition
)
const back = createAsyncRouterMethod(
() => router.back(),
startTransition
)
// Handle transition state changes
useEffect(() => {
if (!isPending) {
routeObserver.notify()
}
}, [isPending])
return {
...router, // Include original router properties
push, // Async push
refresh, // Async refresh
replace, // Async replace
back, // Async back
isPending, // Expose transition state
startTransition // Expose transition control
}
}
Why Share This?
This hook has made navigation smoother for me, and I hope it helps others facing similar challenges. Feel free to try it out and share your feedback!
#Nextjs #React #CustomHook #WebDevelopment
DevOps Engineer | AWS | Azure DevOps | Linux | Google Cloud | Docker | Jenkins | Kubernetes
1 个月Insightful and very helpful. Thanks! Krutik Parikh