This is a short article about implementing routing in your single-page app (SPA) without external libraries. The examples use React, but should port over to your framework of choice. We’ll keep it short and sweet — the routing code itself is just a dozen lines or so.
You can see the app running here: spa-routing.netlify.com
Let’s imagine an app having the following pages:
- Home page: /home.html
- About page: /about
- Landing page for Todos: /todos
- A details page (which is a child of /todos): /todos/1
The details page demonstrates how a parent page can display child routes as children within the parent page — both components being visible at the same time. The approach we’re discussing uses “Dynamic Routing” (in React Router terminology) — which if you’re unfamiliar with can be safely ignored.
Let’s create some to-dos first.
Mount our base component (called Home in the example) with usual techniques. You’ll notice a prop called pathArr, which is an array holding the current location split by the slash.
In an SPA, clicking on links should not send a request to the server, but should call the HTML pushState API. We’ll create a function to give us a click handler we can use in anchor tags (and buttons etc).
You might notice that it also calls a function named storePathInState(). This function (which you’ll see later) just updates our application state with the new url array when it changes. In our trivial example, it will update the state in our container component (Home component). You can store your url state anywhere, such as a redux store.
We also need to handle the back button, right? The window’s onpopstate function gets called every time the back button is clicked or when history.go() is called programmatically. Do the same thing we did earlier — just update the state with an array holding the updated url.
Alright, let’s make the Home component now. There’s nothing much going on here — if the url starts with ‘/about’ show the About component. If the url starts with ‘/todos’ show the TodoList component. Otherwise, show some home page content.
Similarly, here’s the TodoList component which can handle the ‘/todos’ url and the ‘/todos/:id’ child url. When the child url is reached, the TodoDetail child component is displayed as a child of the TodoList component (as React Router does).
We’ve used some rudimentary url matching in our example — which you could replace with more powerful pattern matching.
The complete code for this article can be found at https://gist.github.com/jeswin/ca2fa59d5109a3cbc4fea00ff1cfd068