Keeping track of user URL history

Hey, did you know that the browser has native functionality that maintains the history of pages accessed by a user? As you build up your website, a small UX consideration you might want to make is tracking said URL history to improve the UI.

MDN History API

Scenario 1: Let's say I mozy over to the log in page. Once logged in, maybe the app pushes me to the home page. Cool!

Scenario 2: Now, let's say I want to access a protected route. Once I've logged in, the app should boot me back to the route I was originally trying to access.


To access the location aka URL metadata, React provides a built in hook called useLocation

Usage

import { useLocation } from "react-router-dom"
const location = useLocation()

Console logging the value of location provides you an object that looks something like this:

{pathname: '/home', search: '', hash: '', state: null, key: 'default'}

The main thing we care about here are the pathname and state properties.

Conditionally, if a user hasn't been authenticated, we can use/ask the <Navigate /> component to push them to the /login endpoint.

<Navigate /> accepts a state prop and works cohesively with a users location history. Because of this, we can create a link between the previous attempted path, and a login page.

In our Navigate component definition we create a state object with a new key called "prevLocation", or whatever you want; and give it the value of our location path.

const protectedRoute = () => {
    const isLoggedIn = localStorage.getItem("loggedin")
    const location = useLocation()

    if (!isLoggedIn) {
        return (
            <Navigate 
                to={"/login" }
                state={{
                    prevLocation: location.pathname
                }} 
                replace
            />)
    }
    return <Outlet />
}

After the user is forced to our logic screen, the metadata of location now looks like this: {pathname: '/login', search: '', hash: '', state: {prevLocation: '/home'}, key: 'er30evaf'}

If the user is logged in, then we'll render all of the protected routes via the <Outlet /> component.


On the login page, inside our authentication logic, we can specify that should any state exist in our path metadata, then boot the user back to that path, else just go back to the homepage.

Ignoring what an actual login component might have, a VERY simplified version of the location logic might look something like this:

import { useLocation, useNavigate } from "react-router-dom"
const location = useLocation()
const navigate = useNavigate()
	navigate(
	location.state // If there's state aka `prevLocation`
		? location.state.prevLocation // go to the url they originally wanted
		: "/home", { replace: true } // else, just go back home
	)}

In this example we sub out the component version of <Navigate /> with the useNavigate hook. They are one in the same; all you need to know is that:

== <Navigate /> == - If you need automatic or conditional navigation during the render process (e.g., redirection after successful login etc.).

useNavigate - You need navigation to occur in response to user actions or events (e.g., button click, form submission, or similar interactive events).

If you're wondering what the { replace: true } object is. Similar to a call stack, the browser gives us some built functionality called the History stack. replace = true just means that our navigate hook is going to replace the current location, which at this point would be /login, with the previous location ..

which would be something like:

/blog/secret-post-behind-auth-wall


User-flow

User tries to get this end point

url slug

Is booted to the login

auth deny

  • Previous path was /home/secret
  • Current path after the Navigate push is /login
  • URL history now contains a state object with `prevLocation: '/home/secret'

console log with history obj

User is navigated to the original page after login

happy path