Hash-Based & Push-State URLs In React Apps - Part 1

URL scheme using HTML5 push-state


When you write a React App you need to design the URLs very carefully. That’s because URLs are the main entry way into your app. If you design these routes well, you’ll be able to harness one of the most powerful features of the Web: the link.

The Web link is a feature of the Web so fundamental and easy to implement that developers tend to gloss over its benefits. It’s a feature baked right into the Web platform, and it provides an infinite amount of entry points into your app.

When I started developing Single Page Apps with React Router 4, I didn’t fully understand the difference between <HashRouter> and <BrowserRouter>. I also wasn’t clear as to why there were hash symbols (#) in URLs. I hope this article will help dispell any misunderstandings regarding various URL schemes.

The Two Main URL Schemes

Single Page Applications (a.k.a. React Apps) have two main URL schemes: Hash-Based and Push-State. It’s important to know the benefits of each so that you know what you’re doing. If you’re using a routing library like React Router 4 it’s easy to change from one scheme to another.

Push-State URLs are superior to Hash-Based URLs because they’re “clean”, meaning they’re just normal URLs with no hash symbol. However, Hash-Based URLs have some unique advantages that you must be aware of, and in some contexts are the only viable option. So let’s begin by examining Hash-Based URLs. In some contexts they’re the only viable choice.

Hash-Based URLs

Hash-Based URLs contain a hash symbol (#) that is located after the domain name. This hash symbol, also referred to as a hash fragment, separates the domain name from the rest of the URL. Use this type of scheme when you want to deploy a Single Page Application with multiple client-side routes, but are unable to access server-side code or implement server-side URL redirects. Let me explain.

Notice how in the following Hash-Based URL example, the main domain voicerecordpro.com is separated from the rest of the URL with a hash (#) symbol:

https://voicerecordpro.com/#/recordings/523fac70-6abc-11ey-a371-95dd97e42e90

By browser specification, anything that comes after the hash symbol is never sent to the server. So for the above URL example, the HTTP GET call would look something like this:

GET / HTTP/1.1
HOST www.voicerecordpro.com

Note how the route after the hash symbol, recordings/523fac70-6abc-11ey-a371-95dd97e42e90, is not sent in the HTTP GET call. The only resource requested from this HTTP GET call is “/” which is the main index page of our React App.

Why Is This Useful?

Hash-Based routing is useful when you just want to host a SPA with multiple client-side routes that map to different views, and don’t have access to server code. For example, you may want to host a React App on a static publishing platform like Surge where you don’t have access to a server (the platform just serves static documents).

With Hash-Based URLs, React-Router intercepts everything after the hash symbol and displays the relevant view based on the identifier provided. In developer parlance this is referred to as mapping the current state of the application to the URL.

For the curious, let’s dig a bit deeper and see how the the hash symbol in URLs actually works.

Voice Record Pro recording details route using Hash-Based scheme

The Fragment Identifier

Web browsers have something called fragment identifiers. Originally, fragment identifiers were used to link people to specific sections of a page.

For example, let’s take the following Wikipedia link:

https://en.wikipedia.org/wiki/Fragment_identifier

On the above Wikipedia page, there’s a section titled “Basics” and it has an HTML id of “Basics”. If I wanted to link you directly to that section on the page, I would pass you the following link:

https://en.wikipedia.org/wiki/Fragment_identifier#Basics

Clicking the above link would take you directly to the the “Basics” section, and not at the top of the page. That’s what fragment identifiers were originally intended for. It’s a fundamental feature of Web links that you’ve probably taken for granted.

How The Fragment Identifier Is Used In Routing

JavaScript can access the fragment identifier in the hash property of the object window.location.hash.

> window.location.hash
< "#Basics"

Because JavaScript can access the current fragment identifier in the URL, it can do interesting things like load a specific view given a specific identifier. That’s how basic routing in Single Page Applications on the Web started. Developers basically hacked the fragment identifier.

Hash-Bang “#!” URLs (Deprecated)

There was a point in time when Single Page Apps weren’t crawlable by search engine bots like the GoogleBot. So if you built a suped-up and fast ajax-driven SPA back in the day, you weren’t indexed correctly and therefore lost SEO.

To counter this problem, Google came up with its own proprosal to address the problem, the Hash-Bang (#!) scheme. If an app implemented this scheme, Google would make an extra HTTP GET call using this query key: ?_escaped_fragment_=key=value;

For example. Let’s say you had the following Hash-Bang URL:

https://mydomain.com/#!documents

The GoogleBot would detect that this was an ajax-driven app and would proceed to execute an additional HTTP GET call that would look like this:

https://mydomain.com/?_escaped_fragment_=documents

Provided your server was configured correctly to intercept calls for "_escaped_fragment", it would serve HTML snapshots to the GoogleBot for a given route.

That’s how the #! scheme came about which you may or may not have seen before (Twitter used to use it). However, it’s now DEPRECATED so you should never use this. If you want to use a Hash-Based URL scheme make sure you’re using the “#” symbol only.

Implementing Hash-Based URLs

If you’re using React Router, the Hash-Based URL scheme is very easy to implement. Just import <HashRouter > from React Router and configure your routes.

import { HashRouter } from 'react-router-dom';
...
  <HashRouter>
    <Switch>
      <Route path="/recordings/:id" component={SomeView} />
    </Switch>
  </HashRouter>
...

Now let’s examine why Push-State URLs are the preferable URL scheme to use for React Apps - Part II - Push-State URLs.





GET YOUR LEARNIN' ON

Voice Record Pro brand image

React, Redux & JavaScript are HOT HOT skills that make developers a lot of money.

Learn how to write a professional JavaScript app with a scalable architecture and see how a real-world React App is architected and developed.


LEARN NOW