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 is a codesandbox example of what we’ll be working with.
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;
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.
/home
), navigates away from it, then wants to return to it.These four requirements are what we need to meet in order to proceed with the redirection.
Now let’s jump into the code.
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 setItemmethod.
// router.js
const router = new Router( ... )
router.afterEach(to => {
localStorage.setItem(LS_ROUTE_KEY, to.name)
})
...
export default router
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](https://router.vuejs.org/guide/advanced/navigation-guards.html#global-guards)
. 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 hookIn 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.
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.
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
That’s it! We covered all four of requirements, namely:
localStorage
localStorage
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.
#vuejs #javascript #programming