skip to Main Content

I have an page ‘/message/:id’ with a back button on top left which routes back using router.back() function, Which works perfectly fine when i get routed to that page from any other screen.
But now i’m also sending notification which on click routes to ‘/message/:id’ and since the page it fresh page and has no history to go back the back button doesn’t work.

Is it possible to conditionally route back i.e. if there is any history then use router.back() or it should redirect me to home page (‘/’)
Something like this

if(has page history) {
    router.back();
} else {
    router.redirect('/');
}

2

Answers


  1. Chosen as BEST ANSWER

    This is the same answer given by Fabio Nettis with useEffect instead of hook to track route change.


    Client Component

    This component creates a context that will be set to true when the user uses client side navigation. Therefore, if the context is truthy, the user accesses the next page from within your page.

    "use client";
    
    import { usePathname } from 'next/navigation';
    import { useState, createContext, useEffect, useRef } from 'react';
    
    export const OriginContext = createContext<boolean>(false);
    
    export default function OriginTracker({ children }: React.PropsWithChildren) {
      const [isWithinPage, setIsWithinPage] = useState(false);
      const isInitialLoadRef = useRef(true);
    
      useEffect(() => {
        if (isInitialLoadRef.current) {
          isInitialLoadRef.current = false;
          return;
        }
    
        setIsWithinPage(true);
        return () => setIsWithinPage(false);
      }, [pathname]);
    
      return (
        <OriginContext.Provider value={isWithinPage}>
          {children}
        </OriginContext.Provider>
      );
    }
    

    In your root layout file

    Wrap your layout content inside the OriginTracker component. Don't worry this does not mean that everything is going to be rendered client side, since client components can receive pre-rendered server components as children.

    import OriginTracker from "components/OriginTracker";
    
    export default function RootLayout({ children }: React.PropsWithChildren) {
      return <OriginTracker>{children}</OriginTracker>;
    }
    

    Inside some other component

    Inside your other client components you can use the useContext hook to access the global state to determine where to navigate the user.

    import { useCallback } from "react";
    import { useRouter } from "next/navigation";
    
    import { OriginContext } from "components/OriginTracker";
    
    export default OtherComponent() {
      const router = useRouter();
      const isWithinPage = useContext(OriginContext);
    
      const onClick = useCallback(() => {
        if (isWithinPage) router.back();
        else router.push('/');
      }, [isWithinPage, router]);
    
      return <button onClick={onClick}>Take me back</button>;
    }
    

  2. As far as I know there is no way to check previous entries in the history using the window object due to privacy concerns. A possible solution is to create a client component that will modify a context’ store value upon client side navigation.


    Client Component

    This component creates a context that will be set to true when the user uses client side navigation. Therefore, if the context is truthy, the user accesses the next page from within your page. I have found a very good solution to track client side navigation changes with Next.js 13.

    "use client";
    
    import { useEffect, useState, createContext } from "react";
    
    export const OriginContext = createContext<boolean>(false);
    
    export default function OriginTracker({ children }: React.PropsWithChildren) {
      const [isWithinPage, setIsWithinPage] = useState(false);
    
      // track if the url has changed here (check link)
    
      return (
        <OriginContext.Provider value={isWithinPage}>
          {children}
        </OriginContext.Provider>
      );
    }
    

    In your root layout file

    Wrap your layout content inside the OriginTracker component. Don’t worry this does not mean that everything is going to be rendered client side, since client components can receive pre-rendered server components as children.

    import OriginTracker from "components/OriginTracker";
    
    export default function RootLayout({ children }: React.PropsWithChildren) {
      return <OriginTracker>{children}</OriginTracker>;
    }
    

    Inside some other component

    Inside your other client components you can use the useContext hook to access the global state to determine where to navigate the user.

    import { useCallback } from "react";
    import { useRouter } from "next/navigation";
    
    import { OriginContext } from "components/OriginTracker";
    
    export default OtherComponent() {
      const router = useRouter();
      const isWithinPage = useContext(OriginContext);
    
      const onClick = useCallback(() => {
        if (isWithinPage) router.back();
        else router.replace('/');
      }, [isWithinPage, router]);
    
      return <button onClick={onClick}>Take me back</button>;
    }
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search