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 anelementFactory(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
- Add
/users/:id/posts/:postId
and show both params. - Implement a catch-all route that matches anything under
/docs/*
. - Add a breadcrumb that reflects the current nested route.