React - Routing (Advanced)

Overview

Estimated time: 25–35 minutes

Extend the basic hash router with dynamic parameters, nested routes, and a not-found route.

Try it: Dynamic params and nested routes

View source
// Mini matcher: patterns like /users/:id and /users/:id/settings
function compile(pattern){
  const parts = pattern.split('/').filter(Boolean);
  const keys = [];
  const rx = new RegExp('^/' + parts.map(p => {
    if (p.startsWith(':')) { keys.push(p.slice(1)); return '([^/]+)'; }
    return p.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
  }).join('/') + '$');
  return { rx, keys };
}
function matchRoute(path, routes){
  for (const r of routes){
    const { rx, keys } = r._compiled || (r._compiled = compile(r.path));
    const m = path.match(rx);
    if (m){ const params = {}; keys.forEach((k,i)=> params[k]=decodeURIComponent(m[i+1])); return { ...r, params }; }
  }
  return null;
}
function useHash(){
  const [hash, setHash] = React.useState(() => window.location.hash || '#/');
  React.useEffect(() => { const on=()=>setHash(window.location.hash||'#/'); window.addEventListener('hashchange',on); return ()=>window.removeEventListener('hashchange',on); }, []);
  return hash.replace('#','') || '/';
}
function Link({to, children}){ return {children}; }
function UsersLayout({children}){ return (

Users

{children}
); } function UsersIndex(){ return

Pick a user.

; } function User({params}){ return

User ID: {params.id}

; } function UserSettings({params}){ return

Settings for user {params.id}

; } function NotFound(){ return

Not found.

; } function App(){ const path = useHash(); const routes = [ { path: '/', element:

Home

}, { path: '/users', element: }, { path: '/users/:id', elementFactory: (params) => }, { path: '/users/:id/settings', elementFactory: (params) => }, ]; const m = matchRoute(path, routes); let view = ; if (m){ view = m.element || (m.elementFactory ? m.elementFactory(m.params) : null); } return (
{view}
); } ReactDOM.createRoot(document.getElementById('try-adv-routing')).render();

Syntax primer

  • Compile patterns into regex once and reuse to match path.
  • Route entries can either provide element or an elementFactory(params).
  • Nested UI is composed by rendering children inside a layout component.

Vocabulary

  • Route param: a dynamic segment like :id captured from the URL.
  • Nested route: a route rendered within a parent layout.
  • 404: a Not Found view when no route matches.

Common pitfalls

  • Route ordering matters—put specific routes before general ones.
  • Remember to decodeURIComponent param values.
  • Hash routing doesn’t hit the network, but full URL routing would require server support.

Exercises

  1. Add /users/:id/posts/:postId and show both params.
  2. Implement a catch-all route that matches anything under /docs/*.
  3. Add a breadcrumb that reflects the current nested route.