Async Router for NextJS 14+

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:

  1. Synchronize animations and data fetching during navigation.
  2. Keep application state consistent.
  3. Avoid repeating code for common async navigation patterns.

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

Pavan Panchal

DevOps Engineer | AWS | Azure DevOps | Linux | Google Cloud | Docker | Jenkins | Kubernetes

1 个月

Insightful and very helpful. Thanks! Krutik Parikh

要查看或添加评论,请登录

社区洞察

其他会员也浏览了