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.hashstores a fragment like- #/homethat doesn’t trigger a page reload.
- hashchangeevent 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
- What’s the difference between hash-based routing and history API routing?
- Why doesn’t changing the hash cause a full page reload?
Show answers
- Hash-based uses the URL fragment (#...) and doesn’t touch the server path; history API manipulates the real path and requires server support.
- The fragment is not sent to the server; browsers update it client-side and fire hashchangeevents only.
Exercises
- Add a third page (/settings) and a nav link; verify it responds to back/forward.
- Implement simple route params (e.g., #/user/42) and display the user id.
- Persist the last visited route in localStorageand restore it on load.