React - Routing (Hash)

Overview

Estimated time: 20–30 minutes

Learn a minimal approach to routing without libraries by using the URL hash to pick which view to render.

Learning Objectives

  • Understand the role of a router in SPAs.
  • Implement a tiny hash-based router.

Try it: Tiny Hash Router

View source
const { useState, useEffect } = React;
function useHash(){
  const [hash, setHash] = useState(() => window.location.hash || '#/' );
  useEffect(() => {
    const onHash = () => setHash(window.location.hash || '#/');
    window.addEventListener('hashchange', onHash);
    return () => window.removeEventListener('hashchange', onHash);
  }, []);
  return hash;
}
function App(){
  const hash = useHash();
  let page = hash.replace('#','');
  if (page === '/') page = '/home';
  return (
    <div>
      <nav>
        <a href="#/home">Home</a> | <a href="#/about">About</a>
      </nav>
      {page === '/home' && <h3>Home</h3>}
      {page === '/about' && <h3>About</h3>}
    </div>
  );
}
ReactDOM.createRoot(document.getElementById('try-router')).render(<App />);

Syntax primer

  • window.location.hash stores a fragment like #/home that doesn’t trigger a page reload.
  • hashchange event fires when the hash changes.

Common pitfalls

  • This is a minimal router: no params, nested routes, or guards. Use a routing library for production.

Checks for Understanding

  1. What’s the difference between hash-based routing and history API routing?
  2. Why doesn’t changing the hash cause a full page reload?
Show answers
  1. Hash-based uses the URL fragment (#...) and doesn’t touch the server path; history API manipulates the real path and requires server support.
  2. The fragment is not sent to the server; browsers update it client-side and fire hashchange events only.

Exercises

  1. Add a third page (/settings) and a nav link; verify it responds to back/forward.
  2. Implement simple route params (e.g., #/user/42) and display the user id.
  3. Persist the last visited route in localStorage and restore it on load.