There are situations where keeping a reference to the last route a user visited can come in handy. For example, let’s say we’re working with a multi-step form and the user proceeds from one step to the next. It would be ideal to have the route of that previous step in hand so we know where the user left off, in the event that they navigate away and come back later to complete the form later.
We’re going to cover how to store the last known route and then fetch it when we need it. We’ll be working in Vue in this example and put vue-router to use for routing and localStorage to keep the information about last visited route.
Here’s an example of what we’ll be working with:
First, let’s outline the route structure
Our example has a grand total of three routes:
/home
/hello
/goodbye
Each route needs to be assigned a name property, so let’s add that to our router.js file:
// router.js
import Vue from "vue";
import Router from "vue-router";
import Hello from "@/components/Hello";
import Goodbye from "@/components/Goodbye";
import {
HELLO_URL,
GOODBYE_URL
} from "@/consts";
Vue.use(Router);
const router = new Router({
mode: "history",
routes: [
{ path: "/", name: "home" },
{ path: HELLO_URL, name: "hello", component: Hello },
{ path: GOODBYE_URL, name: "goodbye", component: Goodbye }
]
});
export default router;
Next, let’s go over the requirements
We know the first requirement is to store the last visited route in localStorage
. And, secondly, we need to be able to retrieve it. But what conditions should the route be fetched and applied? That gives us two additional requirements.
- the user enters the main route (
/home
), navigates away from it, then wants to return to it. - the user has been inactive for a specific time period, the session expires, and we want to return the user to the last screen they were on after restarting the session.
These four requirements are what we need to meet in order to proceed with the redirection.
Now let’s jump into the code.
Requirement 1: Save the last route name in localStorage
We want to keep the reference to our last visited route in localStorage
. For example, if a user is at /checkout
and then leaves the site, we want to save that so the purchase can be completed later.
To do that, we want to save the route name when the user enters any new route. We’ll use a navigation guard called afterEach
that’s fired each time the route transition is finished. It provides a to
object which is the target Route Object. In that hook, we can extract the name of that route and save it in localStorage
using a setItem
method.
// router.js
const router = new Router( ... );
router.afterEach(to => {
localStorage.setItem(LS_ROUTE_KEY, to.name);
});
...
export default router;
Requirement 2: Fetch the last route name from localStorage and redirect
Now that the name of the last route is saved, we need to be able to fetch it and trigger a redirect to it when it’s needed. We want to check if we should redirect before we enter a new route, so we will use another navigation guard called beforeEach
. This guard receives three arguments:
to
: the target route objectfrom
: the current route navigated fromnext
: the function that must be called in the guard to resolve the hook
In that guard, we read the name of the last visited route by using a localStorage.getItem()
method. Then, we determine if the user should be redirected. At this point, we check that the target route (to
) is our main route (/home
) and if we do indeed have a last route in localStorage
.
If those conditions are met, we fire the next
method that contains the name of the last visited route. That, in turn, will trigger a redirect to that route.
If any condition fails, then we’ll fire next
without any arguments. That will move the user on to the next hook in the pipeline and proceed with ordinary routing without redirection.
// router.js
const router = new Router( ... );
router.beforeEach((to, from, next) => {
const lastRouteName = localStorage.getItem(LS_ROUTE_KEY);
const shouldRedirect = Boolean(
to.name === "home" &&
lastRouteName
);
if (shouldRedirect) next({ name: lastRouteName });
else next();
});
...
export default router;
That covers two out of four requirements! Let’s proceed with requirement number three.
Requirement 3: The first visit condition
Now, we need to check if the user is visiting the main route for the first time (coming from a different source) or is navigating there from another route within the application. We can do that by adding a flag that is set to true when the Router is created and set it to false after first transition is finished.
// router.js
const router = new Router( ... );
let isFirstTransition = true;
router.beforeEach((to, from, next) => {
const lastRouteName = localStorage.getItem(LS_ROUTE_KEY);
const shouldRedirect = Boolean(
to.name === "home" &&
&& lastRouteName
&& isFirstTransition
);
if (shouldRedirect) next({ name: lastRouteName });
else next();
isFirstTransition = false;
});
...
export default router;
OK, there is one more requirement we need to meet: we want to redirect the user to the last known route if the user has been inactive for longer that a specific period of time.
Requirement 4: The activity time condition
Again, we will use localStorage
to keep the information about user’s last visited route.
In the beforeEach
guard, we will get the route from localStorage
and check if the time passed from that moment is within our threshold (defined by hasBeenActiveRecently
). Then, in our shouldRedirect
, we’ll determine whether a route redirect should happen or not.
We also need to save that information, which we will do in the afterEach
guard.
// router.js
const router = new Router( ... );
let isFirstTransition = true;
router.beforeEach((to, from, next) => {
const lastRouteName = localStorage.getItem(LS_ROUTE_KEY);
const lastActivityAt = localStorage.getItem(LS_LAST_ACTIVITY_AT_KEY);
const hasBeenActiveRecently = Boolean(
lastActivityAt && Date.now() - Number(lastActivityAt) < MAX_TIME_TO_RETURN
);
const shouldRedirect = Boolean(
to.name === "home" &&
&& lastRouteName
&& isFirstTransition
&& hasBeenActiveRecently
);
if (shouldRedirect) next({ name: lastRouteName });
else next();
isFirstTransition = false;
});
router.afterEach(to => {
localStorage.setItem(LS_ROUTE_KEY, to.name);
localStorage.setItem(LS_LAST_ACTIVITY_AT_KEY, Date.now());
});
...
export default router;
We met the requirements!
That’s it! We covered all four of requirements, namely:
- We store the last visited route in
localStorage
- We have a method to retrieve the last visited route from
localStorage
- We redirect a user back to the main route if they’re coming into the application on an initial visit
- We provide the user with a redirect to the last known route within a certain time period
Of course, we can extend this further by adding more complexity to the app and new conditions to the shouldRedirect
variable, but this gives us more than we need to have an understanding of how to keep the last visited route persistent and retrieve it when it’s needed.
Source: CSS-tricks.com