next.jsnext.js13nextjs-dynamic-routingnextjs-app-beta

Await navigation with router from next/navigation


With the old pages router, I could await router.push. I used this to keep a button disabled while we are in the process of navigating to another page:

   async function onSubmit(input: CreatePostFormData) {
        try {
            await BlogApi.createBlogPost(input);
            await router.push("/blog/" + slug);
        } catch (error) {
            console.error(error);
            alert(error);
        }
    }

The new router doesn't return a Promise. Is there a way to achieve a similar behavior without using my own state?


Solution

  • In the past, there was a capability where you could wait for a route transition to complete. However, due to some changes or limitations, this capability is no longer available.

    As an alternative, the suggestion is to attempt wrapping the call to router.push (a method that triggers a route transition) with a startTransition hook. Here it is an example:

    import { useRouter } from 'next/navigation';
    import { useEffect, useState, useTransition } from 'react';
    
    export const useRouterAsync = () => {
      const [isLoadingRouter, setIsLoadingRouter] = useState(true);
      const [isPending, startTransition] = useTransition();
      const router = useRouter();
    
      const handleRoute = async (path: string) => {
        // Note: utilize startTransition because router.push no longer returns a promise.
        startTransition(() => {
          router.push(path);
        });
      };
    
      useEffect(() => {
        if (isPending) {
          return setIsLoadingRouter(true);
        }
        setIsLoadingRouter(false);
      }, [isPending]);
    
      return { handleRoute, isLoadingRouter };
    };
    
    

    NOTE: There's a concern that because the page will probably be unmounted during the transition, certain states or variables, like isPending, may be lost. The consequence of the page unmounting is that the isPending state (likely indicating whether the route transition is pending or not) would be lost, which could be problematic for the functionality of the code.