how to get previous URL in react-router-v6?
Asked Answered
S

2

2

I am using a react-router-v6 and I wanna know is there anyway to log or get previous URL ? I want to use a condition based on my browsing history and check if my previous URL page was x do something otherwise do something else. for example:

const component = ({x: number}) => {
  if (prevUrl === 'someUrl') {
    x + 2;
  } else {
    x - 2;
  }
}

or just simply log prevUrl:

const component = ({x: number}) => {
  consle.log(prevUrl)
}

how can I get prevUrl ?

Stylist answered 18/12, 2022 at 11:24 Comment(1)
Does this help answer your question? https://mcmap.net/q/183377/-how-to-access-history-stack-in-react-router The TL;DR is that you pass along some "state" from the previous page that the current page checks. If the state is the value you expect then you know the previous page, otherwise assume the previous page was anything else and apply the conditional logic accordingly.Odonto
E
1

React router relies on remix-run/history and History Web API.

Alas, neither of them let access the history stack. remix-run/history allows to listen for location changes, but this can't be accessed from the router.

So the conclusion is: there is no built-in way to know the URL of the previous page. If you need it, you will have to build something on your own.

Here is a starter. First prepare a context to provide your history stack:

const myHistoryContext = createContext();

function MyHistoryProvider({ children }) {
  const [myHistory, setMyHistory] = useState([]);

  const push = (location) => setMyHistory([...myHistory, location]);

  return (
    <myHistoryContext.Provider value={{ myHistory, push }}>
      {children}
    </myHistoryContext.Provider>
  );
}

const useMyHistory = () => useContext(myHistoryContext);

A container to keep trace of navigation: this will be used as a nesting route for every pages. The container keeps history up to date by pushing new locations:

function Container() {
  const { push } = useMyHistory();
  const location = useLocation();

  useEffect(() => {
    push(location.pathname);
  }, [location]);

  return <Outlet />;
}

Some pages to be used with the container. Home will display the path of the previous page:

function Home() {
  const { myHistory } = useMyHistory();

  const previous = myHistory[myHistory.length - 2];

  return <h1>Home {previous}</h1>;
}

function Contact() {
  return <h1>Contact</h1>;
}

function About() {
  return <h1>About</h1>;
}

Everything wrapped in App:

function App() {
  return (
    <MyHistoryProvider>
      <BrowserRouter>
        <Link to="/">Home</Link>
        <Link to="/contact">Contact</Link>
        <Link to="/about">About</Link>
        <Routes>
          <Route path="/" element={<Container />}>
            <Route path="/" element={<Home />} />
            <Route path="/contact" element={<Contact />} />
            <Route path="/about" element={<About />} />
          </Route>
        </Routes>
      </BrowserRouter>
    </MyHistoryProvider>
  );
}

A working example on stackblitz: https://stackblitz.com/edit/react-ts-4qykui?file=App.tsx

Some drawbacks:

  • You will only be able to track location changes inside your app. You won't be able to know the external url that led to your app.
  • Reloading the page will clean myHistory.
  • This starter only covers pushing into the stack. Depending on your use case, you might need to handle popping from the stack, e.g. when using the back/forward buttons in your browser.
Exchequer answered 18/12, 2022 at 13:20 Comment(0)
C
1

How to do this in V6 is explained at https://reactrouter.com/en/6.21.2/start/concepts#locations

A couple of great use-cases for location state are:

  • Telling the next page where the user came from and branching the UI...

You need to use location.state, which you can access from useLocation.

Next I show a full example with the various options available to set the state:

Full example

import { Link, useLocation, useNavigate } from 'react-router-dom'

function InitialPage() {
  const navigate = useNavigate()

  if (someCondition) {
    return (
      <Navigate 
        to="/next-page"
        state={{ previousLocationPathname: location.pathname }}
      />
    )
  }

  const onClick = () => {
    navigate('/next-page', { state: { previousLocationPathname: location.pathname } })
  }

  return (
    <div>
      <Button onClick={onClick}>
        Go To Next Page
      </Button>

      <Link
        to="/next-page"
        state={{ previousLocationPathname: location.pathname }}
      >
        Go To Next Page
      </Link>
    </div>
  )
}
function NextPage() {
  const previousLocationPathname: string | undefined =
    useLocation().state.previousLocationPathname

  console.log(previousLocationPathname) // Logs "/initial-page"

  // Branch the UI...
}

Note that in InitialPage I'm using the window.location object, which is fine, and you can also use the location object from useLocation(). On the NextPage you need to use the location from useLocation() though.

Also note that state can be anything you want, so you could for example set it to { from: 'home' } instead of passing the URL. Just be aware that:

Location state values will get serialized, so something like new Date() will be turned into a string.

If you need the query string of the URL (in addition to the pathname I show above), use the location.search field.

Cornell answered 17/1 at 22:3 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.