- What You Will Need
- Creating a Router
- Defining Routes
- Parsing the Current URL
- Matching Routes
- Loading the Initial Route
- Loading Routes
- Adding Navigation
Single-page applications (SPAs) have grown in popularity due to their ability to deliver smooth, uninterrupted user experiences. The magic behind SPAs often lies in a critical component - the router. Routers control the application's views based on the URL, without the need for full-page refreshes.
While several libraries such as React Router for React and Vue Router for Vue.js as well as routers built into frameworks such as express offer robust solutions for managing routes in SPAs, you can build your own rudimentary router in Vanilla JavaScript to understand the underlying mechanics.
What You Will Need
- A basic understanding of JavaScript.
- Knowledge of the HTML5 History API.
- Familiarity with JavaScript Event Listeners.
Creating a Router
Let's start by defining a simple Router
class.
class Router {
constructor(routes) {
this.routes = routes;
this._loadInitialRoute();
}
}
In the constructor, we store the routes passed when instantiating the router and call _loadInitialRoute()
to load the correct view when the application starts.
Defining Routes
Each route is an object with two properties: path
and callback
. path
is the URL at which the route should be triggered, and callback
is the function to execute when the route is activated. Define the routes in an array:
const routes = [
{ path: '/', callback: () => console.log('Home page') },
{ path: '/about', callback: () => console.log('About page') },
];
Parsing the Current URL
To determine which route to load, we need to parse the current URL into a usable format. Let's create a helper method, _getCurrentURL()
, in our Router
class:
class Router {
...
_getCurrentURL() {
const path = window.location.pathname;
return path;
}
...
}
This method uses window.location.pathname
to get the current URL path.
Matching Routes
Next, we add a _matchUrlToRoute()
method that matches the current URL to one of our predefined routes:
class Router {
...
_matchUrlToRoute(urlSegs) {
const matchedRoute = this.routes.find(route => route.path === urlSegs);
return matchedRoute;
}
...
}
Loading the Initial Route
Now we can implement _loadInitialRoute()
. This method will be invoked when the router is instantiated, triggering the correct route based on the current URL:
class Router {
...
_loadInitialRoute() {
const pathnameSplit = window.location.pathname.split('/');
const pathSegs = pathnameSplit.length > 1 ? pathnameSplit.slice(1) : '';
this.loadRoute(...pathSegs);
}
...
}
Loading Routes
The loadRoute()
method takes the URL segments, finds the matching route, and invokes its callback
function:
class Router {
...
loadRoute(...urlSegs) {
const matchedRoute = this._matchUrlToRoute(urlSegs);
if (!matchedRoute) {
throw new Error('Route not found');
}
matchedRoute.callback();
}
...
}
Adding Navigation
To enable navigation, we'll use the history.pushState()
method to change the URL without refreshing the page:
class Router {
...
navigateTo(path) {
window.history.pushState({}, '', path);
this.loadRoute(path);
}
...
}
Now, you can navigate to different routes in your application:
const router = new Router(routes);
router.navigateTo('/about');
Remember to bind the popstate
event to handle the browser's forward and back buttons:
window.addEventListener('popstate', () => {
router._loadInitialRoute();
});
This is a basic example of a router in Vanilla JavaScript. It only scratches the surface of what's possible. The real-world implementations are much more complex and have additional features like route guards, nested routes, and more. But the core idea remains the same, and this foundation can be a stepping stone to more advanced topics.
Interested in proving your knowledge of this topic? Take the JavaScript Fundamentals certification.
JavaScript Fundamentals
Showcase your knowledge of JavaScript in this exam, featuring questions on the language, syntax and features.
$99