Lucepall
Lucepall

Reputation: 341

SingletonRouter is Null using NextJS13 imported from "next/router"

Context

I'm trying to cancel the routing change when the user leaves the page without saving changes. To achieve this in Next.js, I need to listen to routing changes and cancel them using a handler function as middleware to intercept the route change

Like this:

import { Router } from 'next/router'

Router.events.on('routeChangeStart', handleChange)

in order to listen and emit a handler function as middleware to intercept the route changing

Issue

I know NextJS introduced a new Router inside "next/navigation". However when I attempt to import the legacy Router from "next/router" like this:

import SingletonRouter from 'next/router';

the singleton shows a null.

I need to access that singleton in order to prevent routing changes.

I need to access that Router singleton in order to prevent routing changes.

Upvotes: 1

Views: 334

Answers (2)

Fellow Stack
Fellow Stack

Reputation: 26

SingletonRouter exist in the Next 13 using pages directories

You will be able to access the Router legacy hook module from 'next/router" but to access SingletonRouter to emit events, you must use pages folder structure for routing instead of the app folders.

The new Router from 'next/navigation" does not allow you to prevent the routing.

As a workaround, I found that some Next.js projects mix the pages folder and app folder, but I do not recommend this approach.

Here is a example of a repository that is accesses SingletonRouter using pages with Nextjs 13:

https://github.com/codeBelt/warn-unsaved-changes-leaving-web-page-nextjs/tree/typescript

Upvotes: 1

First.. If you use app router. You need to use next/navigation. If you use the pages directory, you can use the next/router package.

Set up state to track changes: First, manage a state variable that tracks whether there are unsaved changes.

import { useEffect, useState } from 'react';
import { useRouter } from 'next/router';

function YourComponent() {
    const [hasUnsavedChanges, setHasUnsavedChanges] = useState(false);
    const router = useRouter();


    const toggleUnsavedChanges = () => setHasUnsavedChanges(!hasUnsavedChanges);
}

Use the beforePopState method to intercept route changes. You can prompt the user with a confirmation dialog to ensure they want to leave the page with unsaved changes.

    useEffect(() => {
        const handleRouteChange = (url) => {
            if (router.asPath !== url && hasUnsavedChanges) {
                if (window.confirm('You have unsaved changes, are you sure you want to leave?')) {
                    // Allow the route change
                    return true;
                } else {
                    // Prevent the route change
                    router.events.emit('routeChangeError');
                    throw 'Route change aborted.';
                }
            }
        }

        router.beforePopState(handleRouteChange);

        return () => {
            router.beforePopState(() => true); // Clean up the listener
        };
    }, [hasUnsavedChanges, router]);

You’ll need to adjust the state based on user interactions that affect whether there are unsaved changes. For instance, modifying a form field would set hasUnsavedChanges to true.

Upvotes: 1

Related Questions