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>;
}